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

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