}
}
-static int save_core(const char *core_path)
+static int copy_fd_simple(int in, int out)
{
- int fd;
static char buf[4096];
int readb, remaining;
- int ret = 0;
+
+ while ((readb = read(in, buf, sizeof(buf))) > 0) {
+ int n;
+
+ for (n = 0, remaining = readb ; remaining > 0; remaining -= n) {
+ n = write(out, buf, remaining);
+ if (n == -1)
+ return -errno;
+ }
+ }
+
+ return 1;
+}
+
+static int copy_fd_splice(int in, int out)
+{
+ ssize_t s;
+ _Bool copied_data = 0;
+
+ const ssize_t max_splice = SSIZE_MAX;
+
+ do {
+ s = splice(in, NULL, out, NULL, max_splice, SPLICE_F_MOVE);
+ // We can try to fallback to simple copy only if first splice failed
+ // (ie. we have not consumed any data yet)
+ if (!copied_data && s > 0)
+ copied_data = 1;
+
+ } while (s > 0);
+
+ if (s < 0)
+ return copied_data ? -errno : 0;
+ else
+ return 1;
+}
+
+static int save_core(const char *core_path)
+{
+ int fd;
+ int r = 0;
fd = open(core_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd == -1) {
return -errno;
}
- while ((readb = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
- int n;
-
- for (n = 0, remaining = readb ; remaining > 0; remaining -= n) {
- n = write(fd, buf, remaining);
- if (n == -1) {
- ret = -errno;
- syslog(LOG_ERR, "crash-pipe: Error while saving core file %s: %m. Removing core.\n", core_path);
- (void)unlink(core_path); // XXX check errors here too
- goto out;
- }
- }
+ r = copy_fd_splice(STDIN_FILENO, fd);
+ if (r == 0) {
+ lseek(fd, SEEK_SET, 0);
+ r = copy_fd_simple(STDIN_FILENO, fd);
+ }
+ if (r < 0) {
+ syslog(LOG_ERR, "crash-pipe: Error while saving core file %s: %m. Removing core.\n", core_path);
+ (void)unlink(core_path); // XXX check errors here too
}
-out:
close(fd);
-
- return ret;
+ return r;
}