Blame SOURCES/0001-mptcpize-use-explicit-file-copy-instead-of-rename-16.patch

0c0d28
From 591b3b168d949c45d5b5994332a3007767845434 Mon Sep 17 00:00:00 2001
0c0d28
Message-Id: <591b3b168d949c45d5b5994332a3007767845434.1638277575.git.dcaratti@redhat.com>
0c0d28
From: Paolo Abeni <paolo.abeni@gmail.com>
0c0d28
Date: Thu, 14 Oct 2021 05:05:54 +0200
0c0d28
Subject: [PATCH] mptcpize: use explicit file copy instead of rename() (#161)
0c0d28
0c0d28
The mentioned syscall fails if the involved files belong to
0c0d28
different fs, which is pretty much expected in the relevant
0c0d28
scenario (tmp file, in tmpfs, and unit file usually under the
0c0d28
root partition)
0c0d28
0c0d28
Instead use sendfile() to explicitly copy all the contents. Note
0c0d28
that we need to close and re-open the unit file, as sendfile()
0c0d28
expect a O_WRITE fd as the target.
0c0d28
---
0c0d28
 src/mptcpize.c | 24 ++++++++++++++++++++----
0c0d28
 1 file changed, 20 insertions(+), 4 deletions(-)
0c0d28
0c0d28
diff --git a/src/mptcpize.c b/src/mptcpize.c
0c0d28
index cb79e09..b502d75 100644
0c0d28
--- a/src/mptcpize.c
0c0d28
+++ b/src/mptcpize.c
0c0d28
@@ -13,6 +13,7 @@
0c0d28
 
0c0d28
 #include <sys/types.h>
0c0d28
 #include <sys/stat.h>
0c0d28
+#include <sys/sendfile.h>
0c0d28
 
0c0d28
 #include <argp.h>
0c0d28
 #include <dlfcn.h>
0c0d28
@@ -163,10 +164,12 @@ static int unit_update(int argc, char *argv[], int enable)
0c0d28
 	char *unit, *line = NULL;
0c0d28
 	int append_env = enable;
0c0d28
 	char dst_path[PATH_MAX];
0c0d28
+	off_t bytes_copied = 0;
0c0d28
+	struct stat fileinfo;
0c0d28
+	int dst, unit_fd;
0c0d28
 	size_t len = 0;
0c0d28
 	ssize_t read;
0c0d28
 	FILE *src;
0c0d28
-	int dst;
0c0d28
 
0c0d28
 	if (argc < 1) {
0c0d28
 		fprintf(stderr, "missing unit argument\n");
0c0d28
@@ -210,11 +213,24 @@ static int unit_update(int argc, char *argv[], int enable)
0c0d28
 		error(1, errno, "can't read from %s", unit);
0c0d28
 	free(line);
0c0d28
 	fclose(src);
0c0d28
-	close(dst);
0c0d28
 
0c0d28
-	if (rename(dst_path, unit) < 0)
0c0d28
-		error(1, errno, "can't rename %s to %s", dst_path, unit);
0c0d28
+	// copy back the modified file into the original unit
0c0d28
+	// note: avoid using rename, as it fails across filesystems
0c0d28
+	if (fstat(dst, &fileinfo) < 0)
0c0d28
+		error(1, errno, "can't stat %s", dst_path);
0c0d28
+
0c0d28
+	// re-open the unit file for writing
0c0d28
+	// mkstemp already opened the temporary file for R/W so we don't need
0c0d28
+	// to touch that file descriptor.
0c0d28
+	unit_fd = open(unit, O_TRUNC | O_RDWR);
0c0d28
+	if (unit_fd < 0)
0c0d28
+		error(1, errno, "can't open %s for writing", unit);
0c0d28
 
0c0d28
+	while (bytes_copied < fileinfo.st_size)
0c0d28
+		if (sendfile(unit_fd, dst, &bytes_copied, fileinfo.st_size - bytes_copied) < 0)
0c0d28
+			error(1, errno, "can't copy from %s to %s", dst_path, unit);
0c0d28
+
0c0d28
+	close(dst);
0c0d28
 	if (system("systemctl daemon-reload") != 0)
0c0d28
 		error(1, errno, "can't reload unit, manual 'systemctl daemon-reload' is required");
0c0d28
 
0c0d28
-- 
0c0d28
2.31.1
0c0d28