[systemd-commits] 14 commits - configure.ac Makefile.am Makefile-man.am man/coredump.conf.xml src/core src/journal src/shared

Zbigniew Jędrzejewski-Szmek zbyszek at kemper.freedesktop.org
Wed Jun 25 22:49:58 PDT 2014


 Makefile-man.am             |    2 
 Makefile.am                 |    5 
 configure.ac                |   22 +++
 man/coredump.conf.xml       |  136 +++++++++++++++++++
 src/core/main.c             |    2 
 src/core/mount-setup.c      |    2 
 src/core/shutdown.c         |   46 ++++--
 src/core/transaction.c      |    2 
 src/journal/compress.c      |  178 ++++++++++++++++++++++----
 src/journal/compress.h      |    4 
 src/journal/coredump.c      |  220 ++++++++++++++++++++++++--------
 src/journal/coredump.conf   |    3 
 src/journal/coredumpctl.c   |  301 ++++++++++++++++++++------------------------
 src/journal/test-compress.c |   54 +++++++
 src/shared/copy.c           |    4 
 15 files changed, 720 insertions(+), 261 deletions(-)

New commits:
commit 375ae4aa4d2f89ae8afdd27e9f2b8336fcc2a046
Author: Uoti Urpala <uoti.urpala at pp1.inet.fi>
Date:   Mon Jun 23 16:50:03 2014 +0300

    core/transaction: fix cycle break attempts outside transaction
    
    Patch fixes some incorrect-looking code in transaction.c.
    It could fix cases where Debian users with bad package configurations
    had systemd go into an infinite loop printing messages about breaking an
    ordering cycle, though I have not reproduced that problem myself.
    
    transaction_verify_order_one() considers jobs/units outside current
    transaction when checking whether ordering dependencies cause cycles.
    It would also incorrectly try to break cycles at these jobs; this
    cannot work, as the break action is to remove the job from the
    transaction, which is a no-op if the job isn't part of the transaction
    to begin with. The unit_matters_to_anchor() test also looks like it
    would not work correctly for non-transaction jobs. Add a check to
    verify that the unit is part of the transaction before considering a
    job a candidate for deletion.
    
    https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=752259

diff --git a/src/core/transaction.c b/src/core/transaction.c
index d23a45c..805d40a 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -381,7 +381,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
                                       "Found dependency on %s/%s",
                                       k->unit->id, job_type_to_string(k->type));
 
-                        if (!delete &&
+                        if (!delete && hashmap_get(tr->jobs, k->unit) &&
                             !unit_matters_to_anchor(k->unit, k)) {
                                 /* Ok, we can drop this one, so let's
                                  * do so. */

commit 0c26bfc3d21fdb3963f1248c237e2f1a33b5566d
Author: Filipe Brandenburger <filbranden at google.com>
Date:   Tue Jun 24 23:06:47 2014 -0700

    build-sys: include PolicyKit files as part of distribution
    
    So that building from an archive works even if intltool is not present.
    The README file already mentioned that intltool should only be required
    when building from git.
    
    Tested: Built it from the distribution archive on a host without intltool.
      $ ./configure --enable-polkit
      $ make

diff --git a/Makefile.am b/Makefile.am
index bfef1c3..e02dede 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5173,7 +5173,7 @@ units/user/%: units/%.m4
 	$(AM_V_M4)$(M4) -P $(M4_DEFINES) -DFOR_USER=1 < $< > $@
 
 if ENABLE_POLKIT
-nodist_polkitpolicy_DATA = \
+dist_polkitpolicy_DATA = \
 	$(polkitpolicy_files) \
 	$(polkitpolicy_in_in_files:.policy.in.in=.policy)
 endif

commit f15515b5e6a9ebe95c938cc670df6e576fcf9176
Author: Filipe Brandenburger <filbranden at google.com>
Date:   Tue Jun 24 23:06:46 2014 -0700

    build-sys: disable NLS support if intltool is not found
    
    IT_PROG_INTLTOOL makes configure fail if intltool is not present.  If we can
    not find intltool, then disable NLS (otherwise make in po/ fails since MSGFMT
    will not be defined.)
    
    Tested: Built it on a host without intltool.
      $ ./configure --enable-nls
      ...
      checking for intltool-merge... no
      configure: error: --enable-nls requested but intltool not found
    
      $ ./configure --disable-polkit
      ...
      checking for intltool-merge... no
      configure: WARNING: *** Disabling NLS support because intltool was not found
      checking whether NLS is requested... no
      ...
      $ make
    
    https://bugs.freedesktop.org/show_bug.cgi?id=79692

diff --git a/configure.ac b/configure.ac
index 31879d3..93aba06 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,18 @@ AS_IF([test "x$enable_static" = "xyes"], [AC_MSG_ERROR([--enable-static is not s
 AS_IF([test "x$enable_largefile" = "xno"], [AC_MSG_ERROR([--disable-largefile is not supported by systemd])])
 
 # i18n stuff for the PolicyKit policy files
+
+# Check whether intltool can be found, disable NLS otherwise
+AC_CHECK_PROG(intltool_found, [intltool-merge], [yes], [no])
+AS_IF([test x"$intltool_found" != xyes],
+      [AS_IF([test x"$enable_nls" = xyes],
+             [AC_MSG_ERROR([--enable-nls requested but intltool not found])],
+             [AS_IF([test x"$enable_nls" != xno],
+                    [AC_MSG_WARN([*** Disabling NLS support because intltool was not found])
+                     enable_nls=no])
+             ])
+      ])
+
 AM_NLS
 AS_IF([test x"$enable_nls" != xno], [
     # intltoolize greps for '^(AC|IT)_PROG_INTLTOOL', so it needs to be on its own line

commit 2f96919bcdd0978164c801b21e053fb3b31e8bac
Author: Filipe Brandenburger <filbranden at google.com>
Date:   Tue Jun 24 23:06:45 2014 -0700

    build-sys: add explicit support for --disable-nls
    
    In particular, disable intltool when --disable-nls is passed to configure.
    
    Tested: Built it on a host without intltool or gettext.
      $ ./configure --disable-nls --disable-polkit
      $ make

diff --git a/configure.ac b/configure.ac
index bb6018f..31879d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,7 +49,17 @@ AS_IF([test "x$enable_static" = "xyes"], [AC_MSG_ERROR([--enable-static is not s
 AS_IF([test "x$enable_largefile" = "xno"], [AC_MSG_ERROR([--disable-largefile is not supported by systemd])])
 
 # i18n stuff for the PolicyKit policy files
+AM_NLS
+AS_IF([test x"$enable_nls" != xno], [
+    # intltoolize greps for '^(AC|IT)_PROG_INTLTOOL', so it needs to be on its own line
 IT_PROG_INTLTOOL([0.40.0])
+])
+
+AS_IF([test -z "$INTLTOOL_POLICY_RULE"], [
+    # If intltool is not available, provide a dummy rule to fail generation of %.policy files with a meaningful error message
+    INTLTOOL_POLICY_RULE='%.policy: %.policy.in ; @echo "  ITMRG   " $@ && echo "*** intltool support required to build target $@" && false'
+    AC_SUBST(INTLTOOL_POLICY_RULE)
+])
 
 GETTEXT_PACKAGE=systemd
 AC_SUBST(GETTEXT_PACKAGE)

commit 908f8b9cbb9432e8a8af39d528e150f1fe11b50e
Author: Tom Hirst <tom.hirst at ipe-systems.co.uk>
Date:   Wed Jun 25 11:45:45 2014 +0000

    core: Don't require cgroups xattr support
    
    Failure to mount cgroups with xattr should not be fatal

diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 991bfdf..206f89a 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -94,7 +94,7 @@ static const MountPoint mount_table[] = {
         { "tmpfs",      "/sys/fs/cgroup",            "tmpfs",      "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
           NULL,       MNT_FATAL|MNT_IN_CONTAINER },
         { "cgroup",     "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
-          NULL,       MNT_FATAL|MNT_IN_CONTAINER },
+          NULL,       MNT_IN_CONTAINER },
         { "cgroup",     "/sys/fs/cgroup/systemd",    "cgroup",     "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
           NULL,       MNT_FATAL|MNT_IN_CONTAINER },
         { "pstore",     "/sys/fs/pstore",            "pstore",     NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,

commit 3210412576857e26c18bd0d154906bd7444f5529
Author: Michael Olbrich <m.olbrich at pengutronix.de>
Date:   Wed Jun 25 14:43:57 2014 +0200

    install: enable timesyncd by default
    
    This treats it similarly to networkd, resolved and others and it matches
    what 90-systemd.preset does.

diff --git a/Makefile.am b/Makefile.am
index 4b292b2..bfef1c3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4301,6 +4301,9 @@ rootlibexec_PROGRAMS += \
 nodist_systemunit_DATA += \
 	units/systemd-timesyncd.service
 
+GENERAL_ALIASES += \
+	$(systemunitdir)/systemd-timesyncd.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-timesyncd.service
+
 EXTRA_DIST += \
 	units/systemd-timesyncd.service.in
 

commit d6239dc4b0cf55a953d6c40890859b85d504ef19
Author: Michał Bartoszkiewicz <mbartoszkiewicz at gmail.com>
Date:   Wed Jun 25 14:54:48 2014 +0200

    core: use correct format string for UIDs

diff --git a/src/core/main.c b/src/core/main.c
index 6981e72..8ee12ef 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1548,7 +1548,7 @@ int main(int argc, char *argv[]) {
                         log_info("Running with unpopulated /etc.");
         } else {
                 _cleanup_free_ char *t = uid_to_name(getuid());
-                log_debug(PACKAGE_STRING " running in user mode for user "PID_FMT"/%s. (" SYSTEMD_FEATURES ")",
+                log_debug(PACKAGE_STRING " running in user mode for user "UID_FMT"/%s. (" SYSTEMD_FEATURES ")",
                           getuid(), t);
         }
 

commit 3cc765d2718ac9b4ff978044ceabf5ad59d73edf
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jun 26 01:02:48 2014 -0400

    man: add coredump.conf(5)

diff --git a/Makefile-man.am b/Makefile-man.am
index 1e4ec67..588bafa 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -664,6 +664,7 @@ endif
 
 if ENABLE_COREDUMP
 MANPAGES += \
+	man/coredump.conf.5 \
 	man/coredumpctl.1
 MANPAGES_ALIAS += \
 	#
@@ -1483,6 +1484,7 @@ EXTRA_DIST += \
 	man/bootctl.xml \
 	man/bootup.xml \
 	man/busctl.xml \
+	man/coredump.conf.xml \
 	man/coredumpctl.xml \
 	man/crypttab.xml \
 	man/daemon.xml \
diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml
new file mode 100644
index 0000000..9e4adff
--- /dev/null
+++ b/man/coredump.conf.xml
@@ -0,0 +1,136 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2014 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
+  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/>.
+-->
+
+<refentry id="coredump.conf" conditional="ENABLE_COREDUMP">
+  <refentryinfo>
+    <title>coredump.conf</title>
+    <productname>systemd</productname>
+
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>Lennart</firstname>
+        <surname>Poettering</surname>
+        <email>lennart at poettering.net</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>coredump.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>coredump.conf</refname>
+    <refpurpose>Coredump storage configuration file</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <para><filename>/etc/systemd/coredump.conf</filename></para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>This file configures the behaviour of <command>systemd-coredump</command>,
+    a handler for core dumps invoked by the kernel.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+
+    <para>All options are configured in the
+    <literal>[Coredump]</literal> section:</para>
+
+    <variablelist>
+
+      <varlistentry>
+        <term><varname>Storage=</varname></term>
+
+        <listitem><para>Controls where to store cores. One of
+        <literal>none</literal>, <literal>external</literal>,
+        <literal>journal</literal>, and <literal>both</literal>. When
+        <literal>none</literal> the coredumps will be logged but not
+        stored permanently. When <literal>external</literal> (the
+        default), cores will be stored in <filename>/var/lib/systemd/coredump</filename>.
+        When <literal>journal</literal>, cores will be stored in
+        the journal and rotated following normal journal
+        rotation patterns. When <literal>both</literal>, cores
+        will be stored in both locations.</para>
+
+        <para>When cores are stored in the journal, they might be
+        compressed following journal compression settings, see
+        <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+        When cores are stored externally, they will be compressed
+        by default, see below.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>Compression=</varname></term>
+
+        <listitem><para>Controls the type of compression for external
+        storage. One of <literal>xz</literal> or
+        <literal>none</literal>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>CompressionLevel=</varname></term>
+
+        <listitem><para>Controls the level of compression for external
+        storage. An integer between 0 and 9. See
+        <citerefentry><refentrytitle>xz</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        for more details.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>ProcessSizeMax=</varname></term>
+
+        <listitem><para>The maximum size in bytes of a core
+        which will be processed. Coredumps exceeding this size
+        will be logged, but the backtrace will not be generated
+        and the core will not be stored.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>ExternalSizeMax=</varname></term>
+        <term><varname>JournalSizeMax=</varname></term>
+
+        <listitem><para>The maximum (uncompressed) size in bytes of a
+        core to be saved.</para></listitem>
+      </varlistentry>
+    </variablelist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>coredumpctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
diff --git a/src/journal/coredump.conf b/src/journal/coredump.conf
index 53e471e..9f4edd3 100644
--- a/src/journal/coredump.conf
+++ b/src/journal/coredump.conf
@@ -9,6 +9,9 @@
 
 [Coredump]
 #Storage=external
+#Compression=xz
+#CompressionLevel=6
+
 #ProcessSizeMax=2G
 #ExternalSizeMax=2G
 #JournalSizeMax=767M

commit 9fe13294a98cb005c9fb0038d01b77c0d9cbfd12
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 25 23:38:49 2014 -0400

    coredump+coredumpctl: add COREDUMP_FILENAME, use in coredumpctl

diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index afd69cd..bb6dcba 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -465,13 +465,13 @@ int main(int argc, char* argv[]) {
         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
-                *coredump_filename = NULL, *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
-                *exe = NULL, *comm = NULL;
+                *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
+                *exe = NULL, *comm = NULL, *filename = NULL;
         const char *info[_INFO_LEN];
 
         _cleanup_close_ int coredump_fd = -1;
 
-        struct iovec iovec[17];
+        struct iovec iovec[18];
         off_t coredump_size;
         int r, j = 0;
         uid_t uid, owner_uid;
@@ -548,15 +548,15 @@ int main(int argc, char* argv[]) {
                         if (arg_storage != COREDUMP_STORAGE_NONE)
                                 arg_storage = COREDUMP_STORAGE_EXTERNAL;
 
-                        r = save_external_coredump(info, uid, &coredump_filename, &coredump_fd, &coredump_size);
+                        r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
                         if (r < 0)
                                 goto finish;
 
-                        r = maybe_remove_external_coredump(coredump_filename, coredump_size);
+                        r = maybe_remove_external_coredump(filename, coredump_size);
                         if (r < 0)
                                 goto finish;
 
-                        log_info("Detected coredump of the journal daemon itself, diverted to %s.", coredump_filename);
+                        log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
                         goto finish;
                 }
 
@@ -647,7 +647,7 @@ int main(int argc, char* argv[]) {
         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
 
         /* Always stream the coredump to disk, if that's possible */
-        r = save_external_coredump(info, uid, &coredump_filename, &coredump_fd, &coredump_size);
+        r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
         if (r < 0)
                 /* skip whole core dumping part */
                 goto log;
@@ -656,9 +656,15 @@ int main(int argc, char* argv[]) {
          * now, as later on we will lack the privileges for
          * it. However, we keep the fd to it, so that we can still
          * process it and log it. */
-        r = maybe_remove_external_coredump(coredump_filename, coredump_size);
+        r = maybe_remove_external_coredump(filename, coredump_size);
         if (r < 0)
                 goto finish;
+        if (r == 0) {
+                const char *coredump_filename;
+
+                coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
+                IOVEC_SET_STRING(iovec[j++], coredump_filename);
+        }
 
         /* Now, let's drop privileges to become the user who owns the
          * segfaulted process and allocate the coredump memory under
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c
index 48e6341..08d8cdf 100644
--- a/src/journal/coredumpctl.c
+++ b/src/journal/coredumpctl.c
@@ -37,6 +37,7 @@
 #include "macro.h"
 #include "journal-internal.h"
 #include "copy.h"
+#include "compress.h"
 
 static enum {
         ACTION_NONE,
@@ -280,55 +281,6 @@ static int retrieve(const void *data,
         return 0;
 }
 
-#define filename_escape(s) xescape((s), "./ ")
-
-static int make_coredump_path(sd_journal *j, char **ret) {
-        _cleanup_free_ char
-                *pid = NULL, *boot_id = NULL, *tstamp = NULL, *comm = NULL,
-                *p = NULL, *b = NULL, *t = NULL, *c = NULL;
-        const void *d;
-        size_t l;
-        char *fn;
-
-        assert(j);
-        assert(ret);
-
-        SD_JOURNAL_FOREACH_DATA(j, d, l) {
-                retrieve(d, l, "COREDUMP_COMM", &comm);
-                retrieve(d, l, "COREDUMP_PID", &pid);
-                retrieve(d, l, "COREDUMP_TIMESTAMP", &tstamp);
-                retrieve(d, l, "_BOOT_ID", &boot_id);
-        }
-
-        if (!pid || !comm || !tstamp || !boot_id) {
-                log_error("Failed to retrieve necessary fields to find coredump on disk.");
-                return -ENOENT;
-        }
-
-        p = filename_escape(pid);
-        if (!p)
-                return log_oom();
-
-        t = filename_escape(tstamp);
-        if (!t)
-                return log_oom();
-
-        c = filename_escape(comm);
-        if (!t)
-                return log_oom();
-
-        b = filename_escape(boot_id);
-        if (!b)
-                return log_oom();
-
-        fn = strjoin("/var/lib/systemd/coredump/core.", c, ".", b, ".", p, ".", t, NULL);
-        if (!fn)
-                return log_oom();
-
-        *ret = fn;
-        return 0;
-}
-
 static void print_field(FILE* file, sd_journal *j) {
         _cleanup_free_ char *value = NULL;
         const void *d;
@@ -349,12 +301,14 @@ static void print_field(FILE* file, sd_journal *j) {
 static int print_list(FILE* file, sd_journal *j, int had_legend) {
         _cleanup_free_ char
                 *pid = NULL, *uid = NULL, *gid = NULL,
-                *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL;
+                *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
+                *filename = NULL;
         const void *d;
         size_t l;
         usec_t t;
         char buf[FORMAT_TIMESTAMP_MAX];
         int r;
+        bool present;
 
         assert(file);
         assert(j);
@@ -367,9 +321,10 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) {
                 retrieve(d, l, "COREDUMP_EXE", &exe);
                 retrieve(d, l, "COREDUMP_COMM", &comm);
                 retrieve(d, l, "COREDUMP_CMDLINE", &cmdline);
+                retrieve(d, l, "COREDUMP_FILENAME", &filename);
         }
 
-        if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline) {
+        if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) {
                 log_warning("Empty coredump log entry");
                 return -EINVAL;
         }
@@ -381,22 +336,25 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) {
         }
 
         format_timestamp(buf, sizeof(buf), t);
+        present = filename && access(filename, F_OK) == 0;
 
         if (!had_legend && !arg_no_legend)
-                fprintf(file, "%-*s %*s %*s %*s %*s %s\n",
+                fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n",
                         FORMAT_TIMESTAMP_WIDTH, "TIME",
                         6, "PID",
                         5, "UID",
                         5, "GID",
                         3, "SIG",
+                        1, "PRESENT",
                            "EXE");
 
-        fprintf(file, "%-*s %*s %*s %*s %*s %s\n",
+        fprintf(file, "%-*s %*s %*s %*s %*s %*s %s\n",
                 FORMAT_TIMESTAMP_WIDTH, buf,
                 6, strna(pid),
                 5, strna(uid),
                 5, strna(gid),
                 3, strna(sgnl),
+                1, present ? "*" : "",
                 strna(exe ?: (comm ?: cmdline)));
 
         return 0;
@@ -408,8 +366,8 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
                 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
                 *unit = NULL, *user_unit = NULL, *session = NULL,
                 *boot_id = NULL, *machine_id = NULL, *hostname = NULL,
-                *coredump = NULL, *slice = NULL, *cgroup = NULL,
-                *owner_uid = NULL, *message = NULL, *timestamp = NULL;
+                *slice = NULL, *cgroup = NULL, *owner_uid = NULL,
+                *message = NULL, *timestamp = NULL, *filename = NULL;
         const void *d;
         size_t l;
         int r;
@@ -432,6 +390,7 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
                 retrieve(d, l, "COREDUMP_SLICE", &slice);
                 retrieve(d, l, "COREDUMP_CGROUP", &cgroup);
                 retrieve(d, l, "COREDUMP_TIMESTAMP", &timestamp);
+                retrieve(d, l, "COREDUMP_FILENAME", &filename);
                 retrieve(d, l, "_BOOT_ID", &boot_id);
                 retrieve(d, l, "_MACHINE_ID", &machine_id);
                 retrieve(d, l, "_HOSTNAME", &hostname);
@@ -546,9 +505,8 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
         if (hostname)
                 fprintf(file, "      Hostname: %s\n", hostname);
 
-        if (make_coredump_path(j, &coredump) >= 0)
-                if (access(coredump, F_OK) >= 0)
-                        fprintf(file, "      Coredump: %s\n", coredump);
+        if (filename && access(filename, F_OK) == 0)
+                fprintf(file, "      Coredump: %s\n", filename);
 
         if (message) {
                 _cleanup_free_ char *m = NULL;
@@ -619,66 +577,131 @@ static int dump_list(sd_journal *j) {
         return 0;
 }
 
-static int dump_core(sd_journal* j) {
-        const void *data;
-        size_t len, ret;
+static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
+        const char *data;
+        _cleanup_free_ char *filename = NULL;
+        size_t len;
         int r;
 
-        assert(j);
+        assert((fd >= 0) != !!path);
+        assert(!!path == !!unlink_temp);
 
-        /* We want full data, nothing truncated. */
-        sd_journal_set_data_threshold(j, 0);
+        /* Prefer uncompressed file to journal (probably cached) to
+         * compressed file (probably uncached). */
+        r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
+        if (r < 0 && r != -ENOENT)
+                log_warning("Failed to retrieve COREDUMP_FILENAME: %s", strerror(-r));
+        else if (r == 0)
+                retrieve(data, len, "COREDUMP_FILENAME", &filename);
 
-        r = focus(j);
-        if (r < 0)
-                return r;
-
-        print_info(output ? stdout : stderr, j, false);
-
-        if (on_tty() && !output) {
-                log_error("Refusing to dump core to tty.");
-                return -ENOTTY;
+        if (filename && access(filename, R_OK) < 0) {
+                log_debug("File %s is not readable: %m", filename);
+                free(filename);
+                filename = NULL;
         }
 
-        r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
-        if (r == ENOENT) {
-                _cleanup_free_ char *fn = NULL;
-                _cleanup_close_ int fd = -1;
+        if (filename && !endswith(filename, ".xz")) {
+                *path = filename;
+                filename = NULL;
 
-                r = make_coredump_path(j, &fn);
-                if (r < 0)
-                        return r;
+                return 0;
+        } else {
+                _cleanup_close_ int fdt = -1;
+                char *temp = NULL;
 
-                fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOCTTY);
                 if (fd < 0) {
-                        if (errno == ENOENT)
+                        temp = strdup("/var/tmp/coredump-XXXXXX");
+                        if (!temp)
+                                return log_oom();
+
+                        fdt = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
+                        if (fdt < 0) {
+                                log_error("Failed to create temporary file: %m");
+                                return -errno;
+                        }
+                        log_debug("Created temporary file %s", temp);
+
+                        fd = fdt;
+                }
+
+                r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
+                if (r == 0) {
+                        ssize_t sz;
+
+                        assert(len >= 9);
+                        data += 9;
+                        len -= 9;
+
+                        sz = write(fdt, data, len);
+                        if (sz < 0) {
+                                log_error("Failed to write temporary file: %m");
+                                r = -errno;
+                                goto error;
+                        }
+                        if (sz != (ssize_t) len) {
+                                log_error("Short write to temporary file.");
+                                r = -EIO;
+                                goto error;
+                        }
+                } else if (filename) {
+                        _cleanup_close_ int fdf;
+
+                        fdf = open(filename, O_RDONLY | O_CLOEXEC);
+                        if (fdf < 0) {
+                                log_error("Failed to open %s: %m", filename);
+                                r = -errno;
+                                goto error;
+                        }
+
+                        r = decompress_stream(fdf, fd, -1);
+                        if (r < 0) {
+                                log_error("Failed to decompress %s: %s", filename, strerror(-r));
+                                goto error;
+                        }
+                } else {
+                        if (r == -ENOENT)
                                 log_error("Coredump neither in journal file nor stored externally on disk.");
                         else
-                                log_error("Failed to open coredump file: %s", strerror(-r));
+                                log_error("Failed to retrieve COREDUMP field: %s", strerror(-r));
+                        goto error;
+                }
 
-                        return -errno;
+                if (temp) {
+                        *path = temp;
+                        *unlink_temp = true;
                 }
 
-                r = copy_bytes(fd, output ? fileno(output) : STDOUT_FILENO, (off_t) -1);
-                if (r < 0) {
-                        log_error("Failed to stream coredump: %s", strerror(-r));
-                        return r;
+                return 0;
+
+error:
+                if (temp) {
+                        unlink(temp);
+                        log_debug("Removed temporary file %s", temp);
                 }
+                return r;
+        }
+}
 
-        } else if (r < 0) {
-                log_error("Failed to retrieve COREDUMP field: %s", strerror(-r));
+static int dump_core(sd_journal* j) {
+        int r;
+
+        assert(j);
+
+        r = focus(j);
+        if (r < 0)
                 return r;
 
-        } else {
-                assert(len >= 9);
-                data = (const uint8_t*) data + 9;
-                len -= 9;
-
-                ret = fwrite(data, len, 1, output ?: stdout);
-                if (ret != 1) {
-                        log_error("Dumping coredump failed: %m (%zu)", ret);
-                        return -errno;
-                }
+        print_info(output ? stdout : stderr, j, false);
+
+        if (on_tty() && !output) {
+                log_error("Refusing to dump core to tty.");
+                return -ENOTTY;
+        }
+
+        r = save_core(j, output ? fileno(output) : STDOUT_FILENO, NULL, NULL);
+        if (r < 0) {
+                log_error("Coredump retrieval failed: %s", strerror(-r));
+                return r;
         }
 
         r = sd_journal_previous(j);
@@ -690,11 +713,9 @@ static int dump_core(sd_journal* j) {
 
 static int run_gdb(sd_journal *j) {
 
-        _cleanup_free_ char *exe = NULL, *coredump = NULL;
-        char temp[] = "/var/tmp/coredump-XXXXXX";
-        bool unlink_temp = false;
-        const char *path;
-        const void *data;
+        _cleanup_free_ char *exe = NULL, *coredump = NULL, *path = NULL;
+        bool unlink_path = false;
+        const char *data;
         siginfo_t st;
         size_t len;
         pid_t pid;
@@ -702,8 +723,6 @@ static int run_gdb(sd_journal *j) {
 
         assert(j);
 
-        sd_journal_set_data_threshold(j, 0);
-
         r = focus(j);
         if (r < 0)
                 return r;
@@ -717,9 +736,9 @@ static int run_gdb(sd_journal *j) {
                 return r;
         }
 
-        assert(len >= 13);
-        data = (const uint8_t*) data + 13;
-        len -= 13;
+        assert(len > strlen("COREDUMP_EXE="));
+        data += strlen("COREDUMP_EXE=");
+        len -= strlen("COREDUMP_EXE=");
 
         exe = strndup(data, len);
         if (!exe)
@@ -735,57 +754,10 @@ static int run_gdb(sd_journal *j) {
                 return -ENOENT;
         }
 
-        r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
-        if (r == -ENOENT) {
-
-                r = make_coredump_path(j, &coredump);
-                if (r < 0)
-                        return r;
-
-                if (access(coredump, R_OK) < 0) {
-                        if (errno == ENOENT)
-                                log_error("Coredump neither in journal file nor stored externally on disk.");
-                        else
-                                log_error("Failed to access coredump file: %m");
-
-                        return -errno;
-                }
-
-                path = coredump;
-
-        } else if (r < 0) {
-                log_error("Failed to retrieve COREDUMP field: %s", strerror(-r));
+        r = save_core(j, -1, &path, &unlink_path);
+        if (r < 0) {
+                log_error("Failed to retrieve core: %s", strerror(-r));
                 return r;
-
-        } else {
-                _cleanup_close_ int fd = -1;
-                ssize_t sz;
-
-                assert(len >= 9);
-                data = (const uint8_t*) data + 9;
-                len -= 9;
-
-                fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
-                if (fd < 0) {
-                        log_error("Failed to create temporary file: %m");
-                        return -errno;
-                }
-
-                unlink_temp = true;
-
-                sz = write(fd, data, len);
-                if (sz < 0) {
-                        log_error("Failed to write temporary file: %m");
-                        r = -errno;
-                        goto finish;
-                }
-                if (sz != (ssize_t) len) {
-                        log_error("Short write to temporary file.");
-                        r = -EIO;
-                        goto finish;
-                }
-
-                path = temp;
         }
 
         pid = fork();
@@ -810,8 +782,10 @@ static int run_gdb(sd_journal *j) {
         r = st.si_code == CLD_EXITED ? st.si_status : 255;
 
 finish:
-        if (unlink_temp)
-                unlink(temp);
+        if (unlink_path) {
+                log_debug("Removed temporary file %s", path);
+                unlink(path);
+        }
 
         return r;
 }
@@ -846,6 +820,9 @@ int main(int argc, char *argv[]) {
                 goto end;
         }
 
+        /* We want full data, nothing truncated. */
+        sd_journal_set_data_threshold(j, 0);
+
         SET_FOREACH(match, matches, it) {
                 r = sd_journal_add_match(j, match, strlen(match));
                 if (r != 0) {

commit 347272731e15d3c4a70fad7ccd7185e8e8059d01
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 25 20:53:40 2014 -0400

    coredump: make compression configurable
    
    Add Compression={none,xz} and CompressionLevel=0-9 settings. Defaults
    are xz/6.
    
    Compression=filesystem may be added later.
    
    I picked "xz" for the compression "type", since we might want to add
    different compressors later on. XZ is fairly memory and CPU intensive, and
    embedded users will likely want to use LZO or some other lightweight compression
    mechanism.

diff --git a/src/journal/compress.c b/src/journal/compress.c
index f36c430..1fc62ea 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -203,7 +203,7 @@ fail:
         return b;
 }
 
-int compress_stream(int fdf, int fdt, off_t max_bytes) {
+int compress_stream(int fdf, int fdt, uint32_t preset, off_t max_bytes) {
         _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
         lzma_ret ret;
 
@@ -213,7 +213,7 @@ int compress_stream(int fdf, int fdt, off_t max_bytes) {
         assert(fdf >= 0);
         assert(fdt >= 0);
 
-        ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
+        ret = lzma_easy_encoder(&s, preset, LZMA_CHECK_CRC64);
         if (ret != LZMA_OK) {
                 log_error("Failed to initialize XZ encoder: code %d", ret);
                 return -EINVAL;
diff --git a/src/journal/compress.h b/src/journal/compress.h
index f37a6b3..f25fe86 100644
--- a/src/journal/compress.h
+++ b/src/journal/compress.h
@@ -35,5 +35,5 @@ bool uncompress_startswith(const void *src, uint64_t src_size,
                            const void *prefix, uint64_t prefix_len,
                            uint8_t extra);
 
-int compress_stream(int fdf, int fdt, off_t max_size);
+int compress_stream(int fdf, int fdt, uint32_t preset, off_t max_size);
 int decompress_stream(int fdf, int fdt, off_t max_size);
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 1c5c99c..afd69cd 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -44,8 +44,14 @@
 #include "compress.h"
 
 #ifdef HAVE_ACL
-#include <sys/acl.h>
-#include "acl-util.h"
+#  include <sys/acl.h>
+#  include "acl-util.h"
+#endif
+
+#ifdef HAVE_XZ
+#  include <lzma.h>
+#else
+#  define LZMA_PRESET_DEFAULT 0
 #endif
 
 /* The maximum size up to which we process coredumps */
@@ -83,11 +89,6 @@ typedef enum CoredumpStorage {
         _COREDUMP_STORAGE_INVALID = -1
 } CoredumpStorage;
 
-static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
-static off_t arg_process_size_max = PROCESS_SIZE_MAX;
-static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
-static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
-
 static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
         [COREDUMP_STORAGE_NONE] = "none",
         [COREDUMP_STORAGE_EXTERNAL] = "external",
@@ -96,15 +97,45 @@ static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
-static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
+static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage,
+                                CoredumpStorage,
+                                "Failed to parse storage setting");
+
+typedef enum CoredumpCompression {
+        COREDUMP_COMPRESSION_NONE,
+        COREDUMP_COMPRESSION_XZ,
+        _COREDUMP_COMPRESSION_MAX,
+        _COREDUMP_COMPRESSION_INVALID = -1
+} CoredumpCompression;
+
+static const char* const coredump_compression_table[_COREDUMP_COMPRESSION_MAX] = {
+        [COREDUMP_COMPRESSION_NONE] = "none",
+        [COREDUMP_COMPRESSION_XZ] = "xz",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_compression, CoredumpCompression);
+static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_compression, coredump_compression,
+                                CoredumpCompression,
+                                "Failed to parse compression setting");
+
+static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
+static CoredumpCompression arg_compression = COREDUMP_COMPRESSION_XZ;
+static unsigned arg_compression_level = LZMA_PRESET_DEFAULT;
+
+static off_t arg_process_size_max = PROCESS_SIZE_MAX;
+static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
+static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
 
 static int parse_config(void) {
 
         static const ConfigTableItem items[] = {
-                { "Coredump", "ProcessSizeMax",  config_parse_iec_off,           0, &arg_process_size_max  },
-                { "Coredump", "ExternalSizeMax", config_parse_iec_off,           0, &arg_external_size_max },
-                { "Coredump", "JournalSizeMax",  config_parse_iec_size,          0, &arg_journal_size_max  },
-                { "Coredump", "Storage",         config_parse_coredump_storage,  0, &arg_storage           },
+                { "Coredump", "Storage",          config_parse_coredump_storage,     0, &arg_storage           },
+                { "Coredump", "Compression",      config_parse_coredump_compression, 0, &arg_compression       },
+                { "Coredump", "CompressionLevel", config_parse_unsigned,             0, &arg_compression_level },
+
+                { "Coredump", "ProcessSizeMax",   config_parse_iec_off,              0, &arg_process_size_max  },
+                { "Coredump", "ExternalSizeMax",  config_parse_iec_off,              0, &arg_external_size_max },
+                { "Coredump", "JournalSizeMax",   config_parse_iec_size,             0, &arg_journal_size_max  },
                 {}
         };
 
@@ -118,6 +149,13 @@ static int parse_config(void) {
                         false,
                         false,
                         NULL);
+
+#ifdef HAVE_XZ
+        if (arg_compression_level > 9) {
+                log_warning("Invalid CompressionLevel %u, ignoring.", arg_compression_level);
+                arg_compression_level = LZMA_PRESET_DEFAULT;
+        }
+#endif
 }
 
 static int fix_acl(int fd, uid_t uid) {
@@ -319,7 +357,8 @@ static int save_external_coredump(const char *info[_INFO_LEN],
 
 #ifdef HAVE_XZ
         /* If we will remove the coredump anyway, do not compress. */
-        if (maybe_remove_external_coredump(NULL, st.st_size) == 0) {
+        if (maybe_remove_external_coredump(NULL, st.st_size) == 0
+            && arg_compression == COREDUMP_COMPRESSION_XZ) {
 
                 _cleanup_free_ char *fn2 = NULL;
                 char *tmp2;
@@ -332,7 +371,7 @@ static int save_external_coredump(const char *info[_INFO_LEN],
                         goto uncompressed;
                 }
 
-                r = compress_stream(fd, fd2, -1);
+                r = compress_stream(fd, fd2, arg_compression_level, -1);
                 if (r < 0) {
                         log_error("Failed to compress %s: %s", tmp2, strerror(-r));
                         unlink_noerrno(tmp2);
@@ -458,7 +497,11 @@ int main(int argc, char* argv[]) {
 
         /* Ignore all parse errors */
         parse_config();
-        log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
+        log_debug("Selected storage '%s'.",
+                  coredump_storage_to_string(arg_storage));
+        log_debug("Selected compression %s:%u.",
+                  coredump_compression_to_string(arg_storage),
+                  arg_compression_level);
 
         r = parse_uid(argv[INFO_UID + 1], &uid);
         if (r < 0) {
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index b098ef9..0806145 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -84,7 +84,7 @@ static void test_compress_stream(const char *srcfile) {
 
         assert_se((dst = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC)) >= 0);
 
-        r = compress_stream(src, dst, -1);
+        r = compress_stream(src, dst, 1, -1);
         assert(r == 0);
 
         assert_se(asprintf(&cmd, "xzcat %s | diff %s -", pattern, srcfile) > 0);

commit cfd652ed617282b06ccbdedb7adc6963b901dde7
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 25 01:03:03 2014 -0400

    coredump: compress core files
    
    Unfortunately the core is first written uncompressed, then compressed
    by reading from disk and writing to the output file. This is ugly and
    slow, but I don't see a way around, if we want to get the backtrace
    without keeping everything in memory.

diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 390f959..1c5c99c 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -41,6 +41,7 @@
 #include "copy.h"
 #include "stacktrace.h"
 #include "path-util.h"
+#include "compress.h"
 
 #ifdef HAVE_ACL
 #include <sys/acl.h>
@@ -195,6 +196,47 @@ static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
 
 #define filename_escape(s) xescape((s), "./ ")
 
+static int fix_permissions(int fd, const char *filename, const char *target,
+                           const char *info[_INFO_LEN], uid_t uid) {
+
+        /* Ignore errors on these */
+        fchmod(fd, 0640);
+        fix_acl(fd, uid);
+        fix_xattr(fd, info);
+
+        if (fsync(fd) < 0) {
+                log_error("Failed to sync coredump %s: %m", filename);
+                return -errno;
+        }
+
+        if (rename(filename, target) < 0) {
+                log_error("Failed to rename coredump %s -> %s: %m", filename, target);
+                return -errno;
+        }
+
+        return 0;
+}
+
+static int maybe_remove_external_coredump(const char *filename, off_t size) {
+
+        /* Returns 1 if might remove, 0 if will not remove, <0 on error. */
+
+        if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
+            size <= arg_external_size_max)
+                return 0;
+
+        if (!filename)
+                return 1;
+
+        if (unlink(filename) < 0) {
+                log_error("Failed to unlink %s: %m", filename);
+                return -errno;
+        }
+
+        return 1;
+}
+
+
 static int save_external_coredump(const char *info[_INFO_LEN],
                                   uid_t uid,
                                   char **ret_filename,
@@ -247,7 +289,7 @@ static int save_external_coredump(const char *info[_INFO_LEN],
 
         fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
         if (fd < 0) {
-                log_error("Failed to create coredump file: %m");
+                log_error("Failed to create coredump file %s: %m", tmp);
                 return -errno;
         }
 
@@ -265,28 +307,66 @@ static int save_external_coredump(const char *info[_INFO_LEN],
                 goto fail;
         }
 
-        /* Ignore errors on these */
-        fchmod(fd, 0640);
-        fix_acl(fd, uid);
-        fix_xattr(fd, info);
-
-        if (fsync(fd) < 0) {
-                log_error("Failed to sync coredump %s: %m", tmp);
-                r = -errno;
-                goto fail;
+        if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
+                log_error("Failed to seek on %s: %m", tmp);
+                goto uncompressed;
         }
 
         if (fstat(fd, &st) < 0) {
                 log_error("Failed to fstat coredump %s: %m", tmp);
-                r = -errno;
                 goto fail;
         }
 
-        if (rename(tmp, fn) < 0) {
-                log_error("Failed to rename coredump %s -> %s: %m", tmp, fn);
-                r = -errno;
-                goto fail;
+#ifdef HAVE_XZ
+        /* If we will remove the coredump anyway, do not compress. */
+        if (maybe_remove_external_coredump(NULL, st.st_size) == 0) {
+
+                _cleanup_free_ char *fn2 = NULL;
+                char *tmp2;
+                _cleanup_close_ int fd2 = -1;
+
+                tmp2 = strappenda(tmp, ".xz");
+                fd2 = open(tmp2, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+                if (fd2 < 0) {
+                        log_error("Failed to create file %s: %m", tmp2);
+                        goto uncompressed;
+                }
+
+                r = compress_stream(fd, fd2, -1);
+                if (r < 0) {
+                        log_error("Failed to compress %s: %s", tmp2, strerror(-r));
+                        unlink_noerrno(tmp2);
+                        goto fail2;
+                }
+
+                fn2 = strappend(fn, ".xz");
+                if (!fn2) {
+                        log_oom();
+                        goto fail2;
+                }
+
+                r = fix_permissions(fd2, tmp2, fn2, info, uid);
+                if (r < 0)
+                        goto fail2;
+
+                *ret_filename = fn2;    /* compressed */
+                *ret_fd = fd;           /* uncompressed */
+                *ret_size = st.st_size; /* uncompressed */
+
+                fn2 = NULL;
+                fd = -1;
+
+                return 0;
+
+        fail2:
+                unlink_noerrno(tmp2);
         }
+#endif
+
+uncompressed:
+        r = fix_permissions(fd, tmp, fn, info, uid);
+        if (r < 0)
+                goto fail;
 
         *ret_filename = fn;
         *ret_fd = fd;
@@ -317,7 +397,7 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
 
         field = malloc(9 + size);
         if (!field) {
-                log_warning("Failed to allocate memory fore coredump, coredump will not be stored.");
+                log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
                 return -ENOMEM;
         }
 
@@ -341,23 +421,6 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
         return 0;
 }
 
-static int maybe_remove_external_coredump(const char *filename, off_t size) {
-
-        if (!filename)
-                return 0;
-
-        if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
-            size <= arg_external_size_max)
-                return 0;
-
-        if (unlink(filename) < 0) {
-                log_error("Failed to unlink %s: %m", filename);
-                return -errno;
-        }
-
-        return 0;
-}
-
 int main(int argc, char* argv[]) {
 
         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,

commit 355b59e252c9910e44a1ad95c045ba8db58a4f6a
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Jun 24 21:24:46 2014 -0400

    journal/compress: add stream compression/decompression functions

diff --git a/src/journal/compress.c b/src/journal/compress.c
index cafe8f4..f36c430 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -22,10 +22,12 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <lzma.h>
 
-#include "macro.h"
 #include "compress.h"
+#include "macro.h"
+#include "util.h"
 
 bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size) {
         lzma_ret ret;
@@ -40,12 +42,12 @@ bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_
          * compressed result is longer than the original */
 
         ret = lzma_easy_buffer_encode(LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE, NULL,
-                                      src, src_size, dst, &out_pos, *dst_size);
+                                      src, src_size, dst, &out_pos, src_size);
         if (ret != LZMA_OK)
                 return false;
 
         /* Is it actually shorter? */
-        if (out_pos == *dst_size)
+        if (out_pos == src_size)
                 return false;
 
         *dst_size = out_pos;
@@ -200,3 +202,149 @@ fail:
 
         return b;
 }
+
+int compress_stream(int fdf, int fdt, off_t max_bytes) {
+        _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
+        lzma_ret ret;
+
+        uint8_t buf[BUFSIZ], out[BUFSIZ];
+        lzma_action action = LZMA_RUN;
+
+        assert(fdf >= 0);
+        assert(fdt >= 0);
+
+        ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
+        if (ret != LZMA_OK) {
+                log_error("Failed to initialize XZ encoder: code %d", ret);
+                return -EINVAL;
+        }
+
+        for (;;) {
+                if (s.avail_in == 0 && action == LZMA_RUN) {
+                        size_t m = sizeof(buf);
+                        ssize_t n;
+
+                        if (max_bytes != -1 && m > (size_t) max_bytes)
+                                m = max_bytes;
+
+                        n = read(fdf, buf, m);
+                        if (n < 0)
+                                return -errno;
+                        if (n == 0)
+                                action = LZMA_FINISH;
+                        else {
+                                s.next_in = buf;
+                                s.avail_in = n;
+
+                                if (max_bytes != -1) {
+                                        assert(max_bytes >= n);
+                                        max_bytes -= n;
+                                }
+                        }
+                }
+
+                if (s.avail_out == 0) {
+                        s.next_out = out;
+                        s.avail_out = sizeof(out);
+                }
+
+                ret = lzma_code(&s, action);
+                if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
+                        log_error("Compression failed: code %d", ret);
+                        return -EBADMSG;
+                }
+
+                if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
+                        ssize_t n, k;
+
+                        n = sizeof(out) - s.avail_out;
+
+                        errno = 0;
+                        k = loop_write(fdt, out, n, false);
+                        if (k < 0)
+                                return k;
+                        if (k != n)
+                                return errno ? -errno : -EIO;
+
+                        if (ret == LZMA_STREAM_END) {
+                                log_debug("Compression finished (%zu -> %zu bytes, %.1f%%)",
+                                          s.total_in, s.total_out,
+                                          (double) s.total_out / s.total_in * 100);
+
+                                return 0;
+                        }
+                }
+        }
+}
+
+int decompress_stream(int fdf, int fdt, off_t max_bytes) {
+        _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
+        lzma_ret ret;
+
+        uint8_t buf[BUFSIZ], out[BUFSIZ];
+        lzma_action action = LZMA_RUN;
+
+        assert(fdf >= 0);
+        assert(fdt >= 0);
+
+        ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
+        if (ret != LZMA_OK) {
+                log_error("Failed to initialize XZ decoder: code %d", ret);
+                return -EINVAL;
+        }
+
+        for (;;) {
+                if (s.avail_in == 0 && action == LZMA_RUN) {
+                        ssize_t n;
+
+                        n = read(fdf, buf, sizeof(buf));
+                        if (n < 0)
+                                return -errno;
+                        if (n == 0)
+                                action = LZMA_FINISH;
+                        else {
+                                s.next_in = buf;
+                                s.avail_in = n;
+                        }
+                }
+
+                if (s.avail_out == 0) {
+                        s.next_out = out;
+                        s.avail_out = sizeof(out);
+                }
+
+                ret = lzma_code(&s, action);
+                if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
+                        log_error("Decompression failed: code %d", ret);
+                        return -EBADMSG;
+                }
+
+                if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
+                        ssize_t n, k;
+
+                        n = sizeof(out) - s.avail_out;
+
+                        if (max_bytes != -1) {
+                                if (max_bytes < n)
+                                        return -E2BIG;
+
+                                max_bytes -= n;
+                        }
+
+                        errno = 0;
+                        k = loop_write(fdt, out, n, false);
+                        if (k < 0)
+                                return k;
+                        if (k != n)
+                                return errno ? -errno : -EIO;
+
+                        if (ret == LZMA_STREAM_END) {
+                                log_debug("Decompression finished (%zu -> %zu bytes, %.1f%%)",
+                                          s.total_in, s.total_out,
+                                          (double) s.total_out / s.total_in * 100);
+
+                                return 0;
+                        }
+                }
+        }
+}
diff --git a/src/journal/compress.h b/src/journal/compress.h
index 2b87e73..f37a6b3 100644
--- a/src/journal/compress.h
+++ b/src/journal/compress.h
@@ -23,6 +23,7 @@
 
 #include <inttypes.h>
 #include <stdbool.h>
+#include <unistd.h>
 
 bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size);
 
@@ -33,3 +34,6 @@ bool uncompress_startswith(const void *src, uint64_t src_size,
                            void **buffer, uint64_t *buffer_size,
                            const void *prefix, uint64_t prefix_len,
                            uint8_t extra);
+
+int compress_stream(int fdf, int fdt, off_t max_size);
+int decompress_stream(int fdf, int fdt, off_t max_size);
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index 15b3f9a..b098ef9 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -68,9 +68,63 @@ static void test_uncompress_startswith(void) {
                                         "barbarbar", 9, ' '));
 }
 
+static void test_compress_stream(const char *srcfile) {
+        _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
+        char pattern[] = "/tmp/systemd-test.xz.XXXXXX",
+             pattern2[] = "/tmp/systemd-test.xz.XXXXXX";
+        int r;
+        _cleanup_free_ char *cmd, *cmd2;
+        struct stat st = {};
+
+        log_debug("/* create source from %s */", srcfile);
+
+        assert_se((src = open(srcfile, O_RDONLY|O_CLOEXEC)) >= 0);
+
+        log_debug("/* test compression */");
+
+        assert_se((dst = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC)) >= 0);
+
+        r = compress_stream(src, dst, -1);
+        assert(r == 0);
+
+        assert_se(asprintf(&cmd, "xzcat %s | diff %s -", pattern, srcfile) > 0);
+        assert_se(system(cmd) == 0);
+
+        log_debug("/* test decompression */");
+
+        assert_se((dst2 = mkostemp_safe(pattern2, O_RDWR|O_CLOEXEC)) >= 0);
+
+        assert_se(stat(srcfile, &st) == 0);
+
+        assert_se(lseek(dst, 0, SEEK_SET) == 0);
+        r = decompress_stream(dst, dst2, st.st_size);
+        assert(r == 0);
+
+        assert_se(asprintf(&cmd2, "diff %s %s", srcfile, pattern2) > 0);
+        assert_se(system(cmd2) == 0);
+
+        log_debug("/* test faulty decompression */");
+
+        assert_se(lseek(dst, 1, SEEK_SET) == 1);
+        r = decompress_stream(dst, dst2, st.st_size);
+        assert(r == -EBADMSG);
+
+        assert_se(lseek(dst, 0, SEEK_SET) == 0);
+        assert_se(lseek(dst2, 0, SEEK_SET) == 0);
+        r = decompress_stream(dst, dst2, st.st_size - 1);
+        assert(r == -E2BIG);
+
+        assert_se(unlink(pattern) == 0);
+        assert_se(unlink(pattern2) == 0);
+}
+
 int main(int argc, char *argv[]) {
+
+        log_set_max_level(LOG_DEBUG);
+
         test_compress_uncompress();
         test_uncompress_startswith();
+        test_compress_stream(argv[0]);
 
         return 0;
 }
diff --git a/src/shared/copy.c b/src/shared/copy.c
index ebd6699..3744797 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -29,9 +29,7 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes) {
         for (;;) {
                 char buf[PIPE_BUF];
                 ssize_t n, k;
-                size_t m;
-
-                m = sizeof(buf);
+                size_t m = sizeof(buf);
 
                 if (max_bytes != (off_t) -1) {
 

commit 76cc0bf682b944d4cb611f1b37c71fce140f8fe7
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Jun 24 21:24:09 2014 -0400

    journal/compress: simplify compress_blob

diff --git a/src/journal/compress.c b/src/journal/compress.c
index a4427be..cafe8f4 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -28,9 +28,8 @@
 #include "compress.h"
 
 bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size) {
-        lzma_stream s = LZMA_STREAM_INIT;
         lzma_ret ret;
-        bool b = false;
+        size_t out_pos = 0;
 
         assert(src);
         assert(src_size > 0);
@@ -40,30 +39,17 @@ bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_
         /* Returns false if we couldn't compress the data or the
          * compressed result is longer than the original */
 
-        ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE);
+        ret = lzma_easy_buffer_encode(LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE, NULL,
+                                      src, src_size, dst, &out_pos, *dst_size);
         if (ret != LZMA_OK)
                 return false;
 
-        s.next_in = src;
-        s.avail_in = src_size;
-        s.next_out = dst;
-        s.avail_out = src_size;
-
-        /* Does it fit? */
-        if (lzma_code(&s, LZMA_FINISH) != LZMA_STREAM_END)
-                goto fail;
-
         /* Is it actually shorter? */
-        if (s.avail_out == 0)
-                goto fail;
-
-        *dst_size = src_size - s.avail_out;
-        b = true;
-
-fail:
-        lzma_end(&s);
+        if (out_pos == *dst_size)
+                return false;
 
-        return b;
+        *dst_size = out_pos;
+        return true;
 }
 
 bool uncompress_blob(const void *src, uint64_t src_size,

commit 8c9778383b2cf64c45323bb10b741aa3beae28ca
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jun 26 01:41:04 2014 -0400

    shutdown: rework messages during shutdown
    
    When running in 'quiet' mode, the only message printed from shutdown
    binary would be 'Cannot finalize remaining file systems and devices,
    giving up.', the only log line at error level before switch back to
    initramfs. This is misleading, because in initramfs everything will
    be cleaned up properly.
    
    Avoid printing anything at error level before the attempt to switch
    back to initramfs. Rework the messages to contain a bit more
    information what is still remaining, to help people diagnose shutdown
    issues.

diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 7ef671a..fde3ce9 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -220,7 +220,7 @@ static int pivot_to_new_root(void) {
 }
 
 int main(int argc, char *argv[]) {
-        bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
+        bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
         bool in_container, use_watchdog = false;
         _cleanup_free_ char *cgroup = NULL;
         char *arguments[3];
@@ -246,8 +246,6 @@ int main(int argc, char *argv[]) {
                 goto error;
         }
 
-        in_container = detect_container(NULL) > 0;
-
         if (streq(arg_verb, "reboot"))
                 cmd = RB_AUTOBOOT;
         else if (streq(arg_verb, "poweroff"))
@@ -275,11 +273,12 @@ int main(int argc, char *argv[]) {
         log_info("Sending SIGKILL to remaining processes...");
         broadcast_signal(SIGKILL, true, false);
 
-        if (in_container) {
-                need_swapoff = false;
-                need_dm_detach = false;
-                need_loop_detach = false;
-        }
+        in_container = detect_container(NULL) > 0;
+
+        need_umount = true;
+        need_swapoff = !in_container;
+        need_loop_detach = !in_container;
+        need_dm_detach = !in_container;
 
         /* Unmount all mountpoints, swaps, and loopback devices */
         for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
@@ -347,23 +346,31 @@ int main(int argc, char *argv[]) {
                         if (retries > 0)
                                 log_info("All filesystems, swaps, loop devices, DM devices detached.");
                         /* Yay, done */
-                        break;
+                        goto initrd_jump;
                 }
 
                 /* If in this iteration we didn't manage to
                  * unmount/deactivate anything, we simply give up */
                 if (!changed) {
-                        log_error("Cannot finalize remaining file systems and devices, giving up.");
-                        break;
+                        log_info("Cannot finalize remaining%s%s%s%s continuing.",
+                                 need_umount ? " file systems," : "",
+                                 need_swapoff ? " swap devices," : "",
+                                 need_loop_detach ? " loop devices," : "",
+                                 need_dm_detach ? " DM devices," : "");
+                        goto initrd_jump;
                 }
 
-                log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
+                log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
+                          retries + 1,
+                          need_umount ? " file systems," : "",
+                          need_swapoff ? " swap devices," : "",
+                          need_loop_detach ? " loop devices," : "",
+                          need_dm_detach ? " DM devices," : "");
         }
 
-        if (retries >= FINALIZE_ATTEMPTS)
-                log_error("Too many iterations, giving up.");
-        else
-                log_info("Storage is finalized.");
+        log_error("Too many iterations, giving up.");
+
+ initrd_jump:
 
         arguments[0] = NULL;
         arguments[1] = arg_verb;
@@ -384,6 +391,13 @@ int main(int argc, char *argv[]) {
                 }
         }
 
+        if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
+                log_error("Failed to finalize %s%s%s%s ignoring",
+                          need_umount ? " file systems," : "",
+                          need_swapoff ? " swap devices," : "",
+                          need_loop_detach ? " loop devices," : "",
+                          need_dm_detach ? " DM devices," : "");
+
         /* The kernel will automaticall flush ATA disks and suchlike
          * on reboot(), but the file systems need to be synce'd
          * explicitly in advance. So let's do this here, but not



More information about the systemd-commits mailing list