+ if (unlink(filename) < 0 && errno != ENOENT)
+ return log_error_errno(errno, "Failed to unlink %s: %m", filename);
+
+ return 1;
+}
+
+static int make_filename(const char *info[_INFO_LEN], char **ret) {
+ _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
+ sd_id128_t boot;
+ int r;
+
+ assert(info);
+
+ c = filename_escape(info[INFO_COMM]);
+ if (!c)
+ return -ENOMEM;
+
+ u = filename_escape(info[INFO_UID]);
+ if (!u)
+ return -ENOMEM;
+
+ r = sd_id128_get_boot(&boot);
+ if (r < 0)
+ return r;
+
+ p = filename_escape(info[INFO_PID]);
+ if (!p)
+ return -ENOMEM;
+
+ t = filename_escape(info[INFO_TIMESTAMP]);
+ if (!t)
+ return -ENOMEM;
+
+ if (asprintf(ret,
+ "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
+ c,
+ u,
+ SD_ID128_FORMAT_VAL(boot),
+ p,
+ t) < 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int save_external_coredump(
+ const char *info[_INFO_LEN],
+ uid_t uid,
+ char **ret_filename,
+ int *ret_fd,
+ off_t *ret_size) {
+
+ _cleanup_free_ char *fn = NULL, *tmp = NULL;
+ _cleanup_close_ int fd = -1;
+ struct stat st;
+ int r;
+
+ assert(info);
+ assert(ret_filename);
+ assert(ret_fd);
+ assert(ret_size);
+
+ r = make_filename(info, &fn);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine coredump file name: %m");
+
+ r = tempfn_random(fn, &tmp);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine temporary file name: %m");
+
+ mkdir_p_label("/var/lib/systemd/coredump", 0755);
+
+ fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
+
+ r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max, false);
+ if (r == -EFBIG) {
+ log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
+ goto fail;
+ } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
+ log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
+ goto fail;
+ } else if (r < 0) {
+ log_error_errno(r, "Failed to dump coredump to file: %m");
+ goto fail;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
+ goto fail;
+ }
+
+ if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
+ log_error_errno(errno, "Failed to seek on %s: %m", tmp);
+ goto fail;
+ }
+
+#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+ /* If we will remove the coredump anyway, do not compress. */
+ if (maybe_remove_external_coredump(NULL, st.st_size) == 0
+ && arg_compress) {
+
+ _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
+ _cleanup_close_ int fd_compressed = -1;
+
+ fn_compressed = strappend(fn, COMPRESSED_EXT);
+ if (!fn_compressed) {
+ log_oom();
+ goto uncompressed;
+ }
+
+ r = tempfn_random(fn_compressed, &tmp_compressed);
+ if (r < 0) {
+ log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed);
+ goto uncompressed;
+ }
+
+ fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+ if (fd_compressed < 0) {
+ log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
+ goto uncompressed;