Blame SOURCES/0313-ccpp-fast-dumping-and-abrt-core-limit.patch

f9f924
From 523792cfbbaf3a5e10cdcb46979739b36ac9c4dd Mon Sep 17 00:00:00 2001
f9f924
From: Martin Kutlak <mkutlak@redhat.com>
f9f924
Date: Wed, 26 Sep 2018 13:24:40 +0200
f9f924
Subject: [PATCH] ccpp: fast dumping and abrt core limit
f9f924
f9f924
This commit introduces a new configuration option MaxCoreFileSize. The
f9f924
option will be compared to MaxCrashReportsSize and the minimum will be
f9f924
used as the limit for the size of the core dump file in a dump directory.
f9f924
f9f924
This commit replaces the read once write twice algorithm with a tee + splice
f9f924
algorithm. tee() does zero copy - it should just increment counters -
f9f924
and splice() moves bytes between file descriptors without the need to
f9f924
copy them to user space. Basically the new algorithm is the same but
f9f924
without the need to copy data to user space. However, the original
f9f924
algorithm was testing the buffer for 0s and if the entire buffer was 0,
f9f924
then lseek() was performed instead of write(). The 0 check was there to
f9f924
make the dumping faster and this is no longer needed as the tee +
f9f924
splice is faster than the original read once write twice algorithm.
f9f924
f9f924
Related: rhbz#1613236
f9f924
f9f924
Signed-off-by: Martin Kutlak <mkutlak@redhat.com>
f9f924
---
f9f924
 doc/abrt-CCpp.conf.txt     |   5 +
f9f924
 src/hooks/CCpp.conf        |  10 +
f9f924
 src/hooks/abrt-hook-ccpp.c | 381 +++++++++++++++++++++++++------------
f9f924
 3 files changed, 274 insertions(+), 122 deletions(-)
f9f924
f9f924
diff --git a/doc/abrt-CCpp.conf.txt b/doc/abrt-CCpp.conf.txt
f9f924
index dffa45dc2..2a626ec49 100644
f9f924
--- a/doc/abrt-CCpp.conf.txt
f9f924
+++ b/doc/abrt-CCpp.conf.txt
f9f924
@@ -19,6 +19,11 @@ MakeCompatCore = 'yes' / 'no' ...::
f9f924
    instead of the template.
f9f924
    For more information about naming core dump files see 'man 5 core'.
f9f924
 
f9f924
+MaxCoreFileSize = 'a number in MiB' ...::
f9f924
+   This configuration option together with MaxCrashReportsSize set the limit on
f9f924
+   the size of dumped core file. The lower value of the both options is used as
f9f924
+   the effective limit. 0 is evaluated as unlimited for the both options.
f9f924
+
f9f924
 SaveBinaryImage = 'yes' / 'no' ...::
f9f924
    Do you want a copy of crashed binary be saved?
f9f924
    Useful, for example, when _deleted binary_ segfaults.
f9f924
diff --git a/src/hooks/CCpp.conf b/src/hooks/CCpp.conf
f9f924
index af31ed53c..48c8c2557 100644
f9f924
--- a/src/hooks/CCpp.conf
f9f924
+++ b/src/hooks/CCpp.conf
f9f924
@@ -9,6 +9,16 @@
f9f924
 # For more information about naming core dump files see 'man 5 core'.
f9f924
 MakeCompatCore = yes
f9f924
 
f9f924
+# The option allows you to set limit for the core file size in MiB.
f9f924
+#
f9f924
+# This value is compared to value of the MaxCrashReportSize configuration
f9f924
+# option from (/etc/abrt.conf) and the lower value is used as the limit.
f9f924
+#
f9f924
+# If MaxCoreFileSize is 0 then the value of MaxCrashReportSize is the limit.
f9f924
+# If MaxCrashReportSize is 0 then the value of MaxCoreFileSize is the limit.
f9f924
+# If both values are 0 then the core file size is unlimited.
f9f924
+MaxCoreFileSize = 0
f9f924
+
f9f924
 # Do you want a copy of crashed binary be saved?
f9f924
 # (useful, for example, when _deleted binary_ segfaults)
f9f924
 SaveBinaryImage = no
f9f924
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
f9f924
index cb4d1e0ce..ca4b61bf1 100644
f9f924
--- a/src/hooks/abrt-hook-ccpp.c
f9f924
+++ b/src/hooks/abrt-hook-ccpp.c
f9f924
@@ -31,6 +31,8 @@
f9f924
 #define  DUMP_SUID_UNSAFE 1
f9f924
 #define  DUMP_SUID_SAFE 2
f9f924
 
f9f924
+#define KERNEL_PIPE_BUFFER_SIZE 65536
f9f924
+
f9f924
 static int g_user_core_flags;
f9f924
 static int g_need_nonrelative;
f9f924
 
f9f924
@@ -54,100 +56,6 @@ static char* malloc_readlink(const char *linkname)
f9f924
     return NULL;
f9f924
 }
f9f924
 
f9f924
-/* Custom version of copyfd_xyz,
f9f924
- * one which is able to write into two descriptors at once.
f9f924
- */
f9f924
-#define CONFIG_FEATURE_COPYBUF_KB 4
f9f924
-static off_t copyfd_sparse(int src_fd, int dst_fd1, int dst_fd2, off_t size2)
f9f924
-{
f9f924
-	off_t total = 0;
f9f924
-	int last_was_seek = 0;
f9f924
-#if CONFIG_FEATURE_COPYBUF_KB <= 4
f9f924
-	char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
f9f924
-	enum { buffer_size = sizeof(buffer) };
f9f924
-#else
f9f924
-	char *buffer;
f9f924
-	int buffer_size;
f9f924
-
f9f924
-	/* We want page-aligned buffer, just in case kernel is clever
f9f924
-	 * and can do page-aligned io more efficiently */
f9f924
-	buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
f9f924
-			PROT_READ | PROT_WRITE,
f9f924
-			MAP_PRIVATE | MAP_ANON,
f9f924
-			/* ignored: */ -1, 0);
f9f924
-	buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
f9f924
-	if (buffer == MAP_FAILED) {
f9f924
-		buffer = alloca(4 * 1024);
f9f924
-		buffer_size = 4 * 1024;
f9f924
-	}
f9f924
-#endif
f9f924
-
f9f924
-	while (1) {
f9f924
-		ssize_t rd = safe_read(src_fd, buffer, buffer_size);
f9f924
-		if (!rd) { /* eof */
f9f924
-			if (last_was_seek) {
f9f924
-				if (lseek(dst_fd1, -1, SEEK_CUR) < 0
f9f924
-				 || safe_write(dst_fd1, "", 1) != 1
f9f924
-				 || (dst_fd2 >= 0
f9f924
-				     && (lseek(dst_fd2, -1, SEEK_CUR) < 0
f9f924
-					 || safe_write(dst_fd2, "", 1) != 1
f9f924
-				        )
f9f924
-				    )
f9f924
-				) {
f9f924
-					perror_msg("Write error");
f9f924
-					total = -1;
f9f924
-					goto out;
f9f924
-				}
f9f924
-			}
f9f924
-			/* all done */
f9f924
-			goto out;
f9f924
-		}
f9f924
-		if (rd < 0) {
f9f924
-			perror_msg("Read error");
f9f924
-			total = -1;
f9f924
-			goto out;
f9f924
-		}
f9f924
-
f9f924
-		/* checking sparseness */
f9f924
-		ssize_t cnt = rd;
f9f924
-		while (--cnt >= 0) {
f9f924
-			if (buffer[cnt] != 0) {
f9f924
-				/* not sparse */
f9f924
-				errno = 0;
f9f924
-				ssize_t wr1 = full_write(dst_fd1, buffer, rd);
f9f924
-				ssize_t wr2 = (dst_fd2 >= 0 ? full_write(dst_fd2, buffer, rd) : rd);
f9f924
-				if (wr1 < rd || wr2 < rd) {
f9f924
-					perror_msg("Write error");
f9f924
-					total = -1;
f9f924
-					goto out;
f9f924
-				}
f9f924
-				last_was_seek = 0;
f9f924
-				goto adv;
f9f924
-			}
f9f924
-		}
f9f924
-		/* sparse */
f9f924
-		xlseek(dst_fd1, rd, SEEK_CUR);
f9f924
-		if (dst_fd2 >= 0)
f9f924
-			xlseek(dst_fd2, rd, SEEK_CUR);
f9f924
-		last_was_seek = 1;
f9f924
- adv:
f9f924
-		total += rd;
f9f924
-		size2 -= rd;
f9f924
-		if (size2 < 0)
f9f924
-			dst_fd2 = -1;
f9f924
-// truncate to 0 or even delete the second file?
f9f924
-// No, kernel does not delete nor truncate core files.
f9f924
-	}
f9f924
- out:
f9f924
-
f9f924
-#if CONFIG_FEATURE_COPYBUF_KB > 4
f9f924
-	if (buffer_size != 4 * 1024)
f9f924
-		munmap(buffer, buffer_size);
f9f924
-#endif
f9f924
-	return total;
f9f924
-}
f9f924
-
f9f924
-
f9f924
 /* Global data */
f9f924
 static char *user_pwd;
f9f924
 static DIR *proc_cwd;
f9f924
@@ -609,13 +517,42 @@ static void create_core_backtrace(pid_t tid, const char *executable, int signal_
f9f924
 #endif /* ENABLE_DUMP_TIME_UNWIND */
f9f924
 }
f9f924
 
f9f924
+static ssize_t splice_entire_per_partes(int in_fd, int out_fd, size_t size_limit)
f9f924
+{
f9f924
+    size_t bytes = 0;
f9f924
+    size_t soft_limit = KERNEL_PIPE_BUFFER_SIZE;
f9f924
+    while (bytes < size_limit)
f9f924
+    {
f9f924
+        const size_t hard_limit = size_limit - bytes;
f9f924
+        if (hard_limit < soft_limit)
f9f924
+            soft_limit = hard_limit;
f9f924
+
f9f924
+        const ssize_t copied = splice(in_fd, NULL, out_fd, NULL, soft_limit, SPLICE_F_MOVE | SPLICE_F_MORE);
f9f924
+        if (copied < 0)
f9f924
+            return copied;
f9f924
+
f9f924
+        bytes += copied;
f9f924
+
f9f924
+        /* Check EOF. */
f9f924
+        if (copied == 0)
f9f924
+            break;
f9f924
+    }
f9f924
+
f9f924
+    return bytes;
f9f924
+}
f9f924
+
f9f924
+
f9f924
 static int create_user_core(int user_core_fd, pid_t pid, off_t ulimit_c)
f9f924
 {
f9f924
     int err = 1;
f9f924
     if (user_core_fd >= 0)
f9f924
     {
f9f924
-        off_t core_size = copyfd_size(STDIN_FILENO, user_core_fd, ulimit_c, COPYFD_SPARSE);
f9f924
-        if (close_user_core(user_core_fd, core_size) != 0)
f9f924
+        errno = 0;
f9f924
+        ssize_t core_size = splice_entire_per_partes(STDIN_FILENO, user_core_fd, ulimit_c);
f9f924
+        if (core_size < 0)
f9f924
+            perror_msg("Failed to create user core '%s' in '%s'", core_basename, user_pwd);
f9f924
+
f9f924
+        if (close_user_core(user_core_fd, core_size) != 0 || core_size < 0)
f9f924
             goto finito;
f9f924
 
f9f924
         err = 0;
f9f924
@@ -732,6 +669,165 @@ static void error_msg_ignore_crash(const char *pid_str, const char *process_str,
f9f924
     return;
f9f924
 }
f9f924
 
f9f924
+static ssize_t splice_full(int in_fd, int out_fd, size_t size)
f9f924
+{
f9f924
+    ssize_t total = 0;
f9f924
+    while (size != 0)
f9f924
+    {
f9f924
+        const ssize_t b = splice(in_fd, NULL, out_fd, NULL, size, 0);
f9f924
+        if (b < 0)
f9f924
+            return b;
f9f924
+
f9f924
+        if (b == 0)
f9f924
+            break;
f9f924
+
f9f924
+        total += b;
f9f924
+        size -= b;
f9f924
+    }
f9f924
+
f9f924
+    return total;
f9f924
+}
f9f924
+
f9f924
+static size_t xsplice_full(int in_fd, int out_fd, size_t size)
f9f924
+{
f9f924
+    const ssize_t r = splice_full(in_fd, out_fd, size);
f9f924
+    if (r < 0)
f9f924
+        perror_msg_and_die("Failed to write core dump to file");
f9f924
+    return (size_t)r;
f9f924
+}
f9f924
+
f9f924
+static void pipe_close(int *pfds)
f9f924
+{
f9f924
+    close(pfds[0]);
f9f924
+    close(pfds[1]);
f9f924
+    pfds[0] = pfds[1] = -1;
f9f924
+}
f9f924
+
f9f924
+enum dump_core_files_ret_flags {
f9f924
+    DUMP_ABRT_CORE_FAILED  = 0x0001,
f9f924
+    DUMP_USER_CORE_FAILED  = 0x0100,
f9f924
+};
f9f924
+
f9f924
+/* Optimized creation of two core files - ABRT and CWD
f9f924
+ *
f9f924
+ * The simplest optimization is to avoid the need to copy data to user space.
f9f924
+ * In that case we cannot read data once and write them twice as we do with
f9f924
+ * read/write approach because there is no syscall forwarding data from a
f9f924
+ * single source fd to several destination fds (one might claim that there is
f9f924
+ * tee() function but such a solution is suboptimal from our perspective).
f9f924
+ *
f9f924
+ * So the function first create ABRT core file and then creates user core file.
f9f924
+ * If ABRT limit made the ABRT core to be smaller than allowed user core size,
f9f924
+ * then the function reads more data from STDIN and appends them to the user
f9f924
+ * core file.
f9f924
+ *
f9f924
+ * We must not read from the user core fd because that operation might be
f9f924
+ * refused by OS.
f9f924
+ */
f9f924
+static int dump_two_core_files(int abrt_core_fd, size_t *abrt_limit, int user_core_fd, size_t *user_limit)
f9f924
+{
f9f924
+   /* tee() does not move the in_fd, thus you need to call splice to be
f9f924
+    * get next chunk of data loaded into the in_fd buffer.
f9f924
+    * So, calling tee() without splice() would be looping on the same
f9f924
+    * data. Hence, we must ensure that after tee() we call splice() and
f9f924
+    * that would be problematic if tee core limit is greater than splice
f9f924
+    * core limit. Therefore, we swap the out fds based on their limits.
f9f924
+    */
f9f924
+    int    spliced_fd          = *abrt_limit > *user_limit ? abrt_core_fd    : user_core_fd;
f9f924
+    size_t spliced_core_limit  = *abrt_limit > *user_limit ? *abrt_limit     : *user_limit;
f9f924
+    int    teed_fd             = *abrt_limit > *user_limit ? user_core_fd    : abrt_core_fd;
f9f924
+    size_t teed_core_limit     = *abrt_limit > *user_limit ? *user_limit     : *abrt_limit;
f9f924
+
f9f924
+    size_t *spliced_core_size  = *abrt_limit > *user_limit ? abrt_limit : user_limit;
f9f924
+    size_t *teed_core_size     = *abrt_limit > *user_limit ? user_limit : abrt_limit;
f9f924
+
f9f924
+    *spliced_core_size = *teed_core_size = 0;
f9f924
+
f9f924
+    int cp[2] = { -1, -1 };
f9f924
+    if (pipe(cp) < 0)
f9f924
+    {
f9f924
+        perror_msg("Failed to create temporary pipe for core file");
f9f924
+        cp[0] = cp[1] = -1;
f9f924
+    }
f9f924
+
f9f924
+    /* tee() can copy duplicate up to size of the pipe buffer bytes.
f9f924
+     * It should not be problem to ask for more (in that case, tee would simply
f9f924
+     * duplicate up to the limit bytes) but I would rather not to exceed
f9f924
+     * the pipe buffer limit.
f9f924
+     */
f9f924
+    int copy_buffer_size = fcntl(STDIN_FILENO, F_GETPIPE_SZ);
f9f924
+    if (copy_buffer_size < 0)
f9f924
+        copy_buffer_size = KERNEL_PIPE_BUFFER_SIZE;
f9f924
+
f9f924
+    ssize_t to_write = copy_buffer_size;
f9f924
+    for (;;)
f9f924
+    {
f9f924
+        if (cp[1] >= 0)
f9f924
+        {
f9f924
+            to_write = tee(STDIN_FILENO, cp[1], copy_buffer_size, 0);
f9f924
+
f9f924
+            /* Check EOF. */
f9f924
+            if (to_write == 0)
f9f924
+                break;
f9f924
+
f9f924
+            if (to_write < 0)
f9f924
+            {
f9f924
+                perror_msg("Cannot duplicate stdin buffer for core file");
f9f924
+                pipe_close(cp);
f9f924
+                to_write = copy_buffer_size;
f9f924
+            }
f9f924
+        }
f9f924
+
f9f924
+        size_t to_splice = to_write;
f9f924
+        if (*spliced_core_size + to_splice > spliced_core_limit)
f9f924
+            to_splice = spliced_core_limit - *spliced_core_size;
f9f924
+
f9f924
+        const size_t spliced = xsplice_full(STDIN_FILENO, spliced_fd, to_splice);
f9f924
+        *spliced_core_size += spliced;
f9f924
+
f9f924
+        if (cp[0] >= 0)
f9f924
+        {
f9f924
+            size_t to_tee = to_write;
f9f924
+            if (*teed_core_size + to_tee > teed_core_limit)
f9f924
+                to_tee = teed_core_limit - *teed_core_size;
f9f924
+
f9f924
+            const ssize_t teed = splice_full(cp[0], teed_fd, to_tee);
f9f924
+            if (teed < 0)
f9f924
+            {
f9f924
+                perror_msg("Cannot splice teed data to core file");
f9f924
+                pipe_close(cp);
f9f924
+                to_write = copy_buffer_size;
f9f924
+            }
f9f924
+            else
f9f924
+                *teed_core_size += teed;
f9f924
+
f9f924
+            if (*teed_core_size >= teed_core_limit)
f9f924
+            {
f9f924
+                pipe_close(cp);
f9f924
+                to_write = copy_buffer_size;
f9f924
+            }
f9f924
+        }
f9f924
+
f9f924
+        /* Check EOF. */
f9f924
+        if (spliced == 0 || *spliced_core_size >= spliced_core_limit)
f9f924
+            break;
f9f924
+    }
f9f924
+
f9f924
+    int r = 0;
f9f924
+    if (cp[0] < 0)
f9f924
+    {
f9f924
+        if (abrt_limit < user_limit)
f9f924
+            r |= DUMP_ABRT_CORE_FAILED;
f9f924
+        else
f9f924
+            r |= DUMP_USER_CORE_FAILED;
f9f924
+    }
f9f924
+    else
f9f924
+        pipe_close(cp);
f9f924
+
f9f924
+    return r;
f9f924
+}
f9f924
+
f9f924
+
f9f924
 int main(int argc, char** argv)
f9f924
 {
f9f924
     int err = 1;
f9f924
@@ -755,6 +851,8 @@ int main(int argc, char** argv)
f9f924
     bool setting_SaveBinaryImage;
f9f924
     bool setting_SaveFullCore;
f9f924
     bool setting_CreateCoreBacktrace;
f9f924
+    unsigned int setting_MaxCoreFileSize = g_settings_nMaxCrashReportsSize;
f9f924
+
f9f924
     GList *setting_ignored_paths = NULL;
f9f924
     GList *setting_allowed_users = NULL;
f9f924
     GList *setting_allowed_groups = NULL;
f9f924
@@ -780,6 +878,18 @@ int main(int argc, char** argv)
f9f924
         if (value)
f9f924
             setting_allowed_groups = parse_list(value);
f9f924
 
f9f924
+        value = get_map_string_item_or_NULL(settings, "MaxCoreFileSize");
f9f924
+        if (value)
f9f924
+        {
f9f924
+            char *end;
f9f924
+            errno = 0;
f9f924
+            unsigned long ul = strtoul(value, &end, 10);
f9f924
+            if (errno || end == value || *end != '\0' || ul > UINT_MAX)
f9f924
+                error_msg("The MaxCoreFileSize option in the CCpp.conf file holds an invalid value");
f9f924
+            else
f9f924
+                setting_MaxCoreFileSize = ul;
f9f924
+        }
f9f924
+
f9f924
         setting_CreateCoreBacktrace = value ? string_to_bool(value) : true;
f9f924
         value = get_map_string_item_or_NULL(settings, "VerboseLog");
f9f924
         if (value)
f9f924
@@ -1019,8 +1129,8 @@ int main(int argc, char** argv)
f9f924
 
f9f924
         unlink(path);
f9f924
         int abrt_core_fd = xopen3(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
f9f924
-        off_t core_size = copyfd_eof(STDIN_FILENO, abrt_core_fd, COPYFD_SPARSE);
f9f924
-        if (core_size < 0 || fsync(abrt_core_fd) != 0)
f9f924
+        off_t core_size = splice_entire_per_partes(STDIN_FILENO, abrt_core_fd, SIZE_MAX);
f9f924
+        if (core_size < 0 || fsync(abrt_core_fd) != 0 || close(abrt_core_fd) < 0)
f9f924
         {
f9f924
             unlink(path);
f9f924
             /* copyfd_eof logs the error including errno string,
f9f924
@@ -1133,31 +1243,58 @@ int main(int argc, char** argv)
f9f924
             close(src_fd_binary);
f9f924
         }
f9f924
 
f9f924
-        off_t core_size = 0;
f9f924
+        size_t core_size = 0;
f9f924
         if (setting_SaveFullCore)
f9f924
         {
f9f924
-            strcpy(path + path_len, "/"FILENAME_COREDUMP);
f9f924
-            int abrt_core_fd = create_or_die(path, user_core_fd);
f9f924
-
f9f924
-            /* We write both coredumps at once.
f9f924
-             * We can't write user coredump first, since it might be truncated
f9f924
-             * and thus can't be copied and used as abrt coredump;
f9f924
-             * and if we write abrt coredump first and then copy it as user one,
f9f924
-             * then we have a race when process exits but coredump does not exist yet:
f9f924
-             * $ echo -e '#include<signal.h>\nmain(){raise(SIGSEGV);}' | gcc -o test -x c -
f9f924
-             * $ rm -f core*; ulimit -c unlimited; ./test; ls -l core*
f9f924
-             * 21631 Segmentation fault (core dumped) ./test
f9f924
-             * ls: cannot access core*: No such file or directory <=== BAD
f9f924
-             */
f9f924
-            core_size = copyfd_sparse(STDIN_FILENO, abrt_core_fd, user_core_fd, ulimit_c);
f9f924
-            close_user_core(user_core_fd, core_size);
f9f924
-            if (fsync(abrt_core_fd) != 0 || close(abrt_core_fd) != 0 || core_size < 0)
f9f924
+            int abrt_core_fd = dd_open_item(dd, FILENAME_COREDUMP, O_RDWR);
f9f924
+            if (abrt_core_fd < 0)
f9f924
+            {   /* Avoid the need to deal with two destinations. */
f9f924
+                perror_msg("Failed to create ABRT core file in '%s'", dd->dd_dirname);
f9f924
+                create_user_core(user_core_fd, pid, ulimit_c);
f9f924
+            }
f9f924
+            else
f9f924
             {
f9f924
-                unlink(path);
f9f924
-                dd_delete(dd);
f9f924
-                /* copyfd_sparse logs the error including errno string,
f9f924
-                 * but it does not log file name */
f9f924
-                error_msg_and_die("Error writing '%s'", path);
f9f924
+                size_t abrt_limit = 0;
f9f924
+                if (   (g_settings_nMaxCrashReportsSize != 0 && setting_MaxCoreFileSize == 0)
f9f924
+                    || (g_settings_nMaxCrashReportsSize != 0 && g_settings_nMaxCrashReportsSize < setting_MaxCoreFileSize))
f9f924
+                    abrt_limit = g_settings_nMaxCrashReportsSize;
f9f924
+                else
f9f924
+                    abrt_limit = setting_MaxCoreFileSize;
f9f924
+
f9f924
+                if (abrt_limit != 0)
f9f924
+                {
f9f924
+                    const size_t abrt_limit_bytes = 1024 * 1024 * abrt_limit;
f9f924
+                    /* Overflow protection. */
f9f924
+                    if (abrt_limit_bytes > abrt_limit)
f9f924
+                        abrt_limit = abrt_limit_bytes;
f9f924
+                    else
f9f924
+                    {
f9f924
+                        error_msg("ABRT core file size limit (MaxCrashReportsSize|MaxCoreFileSize) does not fit into runtime type. Using maximal possible size.");
f9f924
+                        abrt_limit = SIZE_MAX;
f9f924
+                    }
f9f924
+                }
f9f924
+                else
f9f924
+                    abrt_limit = SIZE_MAX;
f9f924
+
f9f924
+                if (user_core_fd < 0)
f9f924
+                {
f9f924
+                    const ssize_t r = splice_entire_per_partes(STDIN_FILENO, abrt_core_fd, abrt_limit);
f9f924
+                    if (r < 0)
f9f924
+                        perror_msg("Failed to write ABRT core file");
f9f924
+                    else
f9f924
+                        core_size = r;
f9f924
+                }
f9f924
+                else
f9f924
+                {
f9f924
+                    size_t user_limit = ulimit_c;
f9f924
+                    const int r = dump_two_core_files(abrt_core_fd, &abrt_limit, user_core_fd, &user_limit);
f9f924
+                    close_user_core(user_core_fd, (r & DUMP_USER_CORE_FAILED) ? -1 : user_limit);
f9f924
+                    if (!(r & DUMP_ABRT_CORE_FAILED))
f9f924
+                        core_size = abrt_limit;
f9f924
+                }
f9f924
+
f9f924
+                if (fsync(abrt_core_fd) != 0 || close(abrt_core_fd) != 0)
f9f924
+                    perror_msg("Failed to close ABRT core file");
f9f924
             }
f9f924
         }
f9f924
         else
f9f924
@@ -1223,8 +1360,8 @@ int main(int argc, char** argv)
f9f924
         free(newpath);
f9f924
 
f9f924
         if (core_size > 0)
f9f924
-            log_notice("Saved core dump of pid %lu (%s) to %s (%llu bytes)",
f9f924
-                       (long)pid, executable, path, (long long)core_size);
f9f924
+            log_notice("Saved core dump of pid %lu (%s) to %s (%zu bytes)",
f9f924
+                       (long)pid, executable, path, core_size);
f9f924
 
f9f924
         notify_new_path(path);
f9f924
 
f9f924
-- 
f9f924
2.17.2
f9f924