summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2010-05-12 19:55:06 +0100
committerRichard Jones <rjones@redhat.com>2010-05-13 17:08:02 +0100
commitdc706a639eec16084c0618baf7bfde00c6565f63 (patch)
treee96751894fe49bf81e704436fc089a173b0f44fc /daemon
parent11a2ad8c9a1da7fe7f8142be69312d0cb5979e0a (diff)
downloadlibguestfs-dc706a639eec16084c0618baf7bfde00c6565f63.tar.gz
libguestfs-dc706a639eec16084c0618baf7bfde00c6565f63.tar.xz
libguestfs-dc706a639eec16084c0618baf7bfde00c6565f63.zip
Fix FileIn cmds losing synch if both ends send cancel messages (RHBZ#576879).
During a FileIn command (eg. upload, tar-in) if both sides experience errors, then both sides could send cancel messages, the result being lost synchronization. The reason for the lost synch was because the daemon was ignoring this case and sending an error message back which the library side (which had cancelled) was not expecting. Fix this by checking in the daemon for the case where the library also cancels during daemon cancellation, and not sending an error messages. This also includes an enhanced regression test which checks for this case. This extends the original fix in commit 5922d7084d6b43f0a1a15b664c7082dfeaf584d0. More details can be found here: https://bugzilla.redhat.com/show_bug.cgi?id=576879#c5
Diffstat (limited to 'daemon')
-rw-r--r--daemon/command.c2
-rw-r--r--daemon/daemon.h26
-rw-r--r--daemon/df.c4
-rw-r--r--daemon/inotify.c2
-rw-r--r--daemon/mount.c8
-rw-r--r--daemon/proto.c6
-rw-r--r--daemon/tar.c34
-rw-r--r--daemon/upload.c13
8 files changed, 51 insertions, 44 deletions
diff --git a/daemon/command.c b/daemon/command.c
index 5e870673..48bed2de 100644
--- a/daemon/command.c
+++ b/daemon/command.c
@@ -36,7 +36,7 @@ do_command (char *const *argv)
int dev_ok, dev_pts_ok, proc_ok, selinux_ok, sys_ok;
/* We need a root filesystem mounted to do this. */
- NEED_ROOT (, return NULL);
+ NEED_ROOT (0, return NULL);
/* Conveniently, argv is already a NULL-terminated argv-style array
* of parameters, so we can pass it straight in to our internal
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 977dfdcb..de598cd3 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -139,10 +139,13 @@ typedef int (*receive_cb) (void *opaque, const void *buf, size_t len);
extern int receive_file (receive_cb cb, void *opaque);
/* daemon functions that receive files (FileIn) can call this
- * to cancel incoming transfers (eg. if there is a local error),
- * but they MUST then call reply_with_*.
+ * to cancel incoming transfers (eg. if there is a local error).
+ *
+ * If and only if this function does NOT return -2, they MUST then
+ * call reply_with_*
+ * (see https://bugzilla.redhat.com/show_bug.cgi?id=576879#c5).
*/
-extern void cancel_receive (void);
+extern int cancel_receive (void);
/* daemon functions that return files (FileOut) should call
* reply, then send_file_* for each FileOut parameter.
@@ -160,8 +163,8 @@ extern void reply (xdrproc_t xdrp, char *ret);
#define NEED_ROOT(cancel_stmt,fail_stmt) \
do { \
if (!root_mounted) { \
- cancel_stmt; \
- reply_with_error ("%s: you must call 'mount' first to mount the root filesystem", __func__); \
+ if ((cancel_stmt) != -2) \
+ reply_with_error ("%s: you must call 'mount' first to mount the root filesystem", __func__); \
fail_stmt; \
} \
} \
@@ -173,8 +176,8 @@ extern void reply (xdrproc_t xdrp, char *ret);
#define ABS_PATH(path,cancel_stmt,fail_stmt) \
do { \
if ((path)[0] != '/') { \
- cancel_stmt; \
- reply_with_error ("%s: path must start with a / character", __func__); \
+ if ((cancel_stmt) != -2) \
+ reply_with_error ("%s: path must start with a / character", __func__); \
fail_stmt; \
} \
} while (0)
@@ -189,15 +192,16 @@ extern void reply (xdrproc_t xdrp, char *ret);
#define RESOLVE_DEVICE(path,cancel_stmt,fail_stmt) \
do { \
if (STRNEQLEN ((path), "/dev/", 5)) { \
- cancel_stmt; \
- reply_with_error ("%s: %s: expecting a device name", __func__, (path)); \
+ if ((cancel_stmt) != -2) \
+ reply_with_error ("%s: %s: expecting a device name", __func__, (path)); \
fail_stmt; \
} \
if (device_name_translation ((path)) == -1) { \
int err = errno; \
- cancel_stmt; \
+ int r = cancel_stmt; \
errno = err; \
- reply_with_perror ("%s: %s", __func__, path); \
+ if (r != -2) \
+ reply_with_perror ("%s: %s", __func__, path); \
fail_stmt; \
} \
} while (0)
diff --git a/daemon/df.c b/daemon/df.c
index 7aa6f4fd..cce41a0e 100644
--- a/daemon/df.c
+++ b/daemon/df.c
@@ -33,7 +33,7 @@ do_df (void)
int r;
char *out, *err;
- NEED_ROOT (, return NULL);
+ NEED_ROOT (0, return NULL);
r = command (&out, &err, "df", NULL);
if (r == -1) {
@@ -54,7 +54,7 @@ do_df_h (void)
int r;
char *out, *err;
- NEED_ROOT (, return NULL);
+ NEED_ROOT (0, return NULL);
r = command (&out, &err, "df", "-h", NULL);
if (r == -1) {
diff --git a/daemon/inotify.c b/daemon/inotify.c
index 104fa60b..d5a5a73e 100644
--- a/daemon/inotify.c
+++ b/daemon/inotify.c
@@ -70,7 +70,7 @@ do_inotify_init (int max_events)
#ifdef HAVE_SYS_INOTIFY_H
FILE *fp;
- NEED_ROOT (, return -1);
+ NEED_ROOT (0, return -1);
if (max_events < 0) {
reply_with_error ("max_events < 0");
diff --git a/daemon/mount.c b/daemon/mount.c
index 8927c6c2..54851168 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -48,7 +48,7 @@ do_mount_vfs (const char *options, const char *vfstype,
char *mp;
char *error;
- ABS_PATH (mountpoint, , return -1);
+ ABS_PATH (mountpoint, 0, return -1);
is_root = STREQ (mountpoint, "/");
@@ -121,7 +121,7 @@ do_umount (const char *pathordevice)
}
if (is_dev)
- RESOLVE_DEVICE (buf, , { free (buf); return -1; });
+ RESOLVE_DEVICE (buf, 0, { free (buf); return -1; });
r = command (NULL, &err, "umount", buf, NULL);
free (buf);
@@ -356,7 +356,7 @@ do_mkmountpoint (const char *path)
int r;
/* NEED_ROOT (return -1); - we don't want this test for this call. */
- ABS_PATH (path, , return -1);
+ ABS_PATH (path, 0, return -1);
CHROOT_IN;
r = mkdir (path, 0777);
@@ -381,7 +381,7 @@ do_rmmountpoint (const char *path)
int r;
/* NEED_ROOT (return -1); - we don't want this test for this call. */
- ABS_PATH (path, , return -1);
+ ABS_PATH (path, 0, return -1);
CHROOT_IN;
r = rmdir (path);
diff --git a/daemon/proto.c b/daemon/proto.c
index ee1c400d..6fa243ff 100644
--- a/daemon/proto.c
+++ b/daemon/proto.c
@@ -395,7 +395,7 @@ receive_file (receive_cb cb, void *opaque)
}
/* Send a cancellation flag back to the library. */
-void
+int
cancel_receive (void)
{
XDR xdr;
@@ -408,11 +408,11 @@ cancel_receive (void)
if (xwrite (sock, fbuf, sizeof fbuf) == -1) {
perror ("write to socket");
- return;
+ return -1;
}
/* Keep receiving chunks and discarding, until library sees cancel. */
- (void) receive_file (NULL, NULL);
+ return receive_file (NULL, NULL);
}
static int check_for_library_cancellation (void);
diff --git a/daemon/tar.c b/daemon/tar.c
index 26a0d302..3f5f60a6 100644
--- a/daemon/tar.c
+++ b/daemon/tar.c
@@ -45,9 +45,9 @@ do_tar_in (const char *dir)
/* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
if (asprintf_nowarn (&cmd, "tar -C %R -xf -", dir) == -1) {
err = errno;
- cancel_receive ();
+ r = cancel_receive ();
errno = err;
- reply_with_perror ("asprintf");
+ if (r != -2) reply_with_perror ("asprintf");
return -1;
}
@@ -57,9 +57,9 @@ do_tar_in (const char *dir)
fp = popen (cmd, "w");
if (fp == NULL) {
err = errno;
- cancel_receive ();
+ r = cancel_receive ();
errno = err;
- reply_with_perror ("%s", cmd);
+ if (r != -2) reply_with_perror ("%s", cmd);
free (cmd);
return -1;
}
@@ -72,8 +72,8 @@ do_tar_in (const char *dir)
r = receive_file (write_cb, &fd);
if (r == -1) { /* write error */
- cancel_receive ();
- reply_with_error ("write error on directory: %s", dir);
+ if (cancel_receive () != -2)
+ reply_with_error ("write error on directory: %s", dir);
pclose (fp);
return -1;
}
@@ -85,8 +85,9 @@ do_tar_in (const char *dir)
if (pclose (fp) != 0) {
if (r == -1) /* if r == 0, file transfer ended already */
- cancel_receive ();
- reply_with_error ("tar subcommand failed on directory: %s", dir);
+ r = cancel_receive ();
+ if (r != -2)
+ reply_with_error ("tar subcommand failed on directory: %s", dir);
return -1;
}
@@ -162,9 +163,9 @@ do_tXz_in (const char *dir, char filter)
/* "tar -C /sysroot%s -zxf -" but we have to quote the dir. */
if (asprintf_nowarn (&cmd, "tar -C %R -%cxf -", dir, filter) == -1) {
err = errno;
- cancel_receive ();
+ r = cancel_receive ();
errno = err;
- reply_with_perror ("asprintf");
+ if (r != -2) reply_with_perror ("asprintf");
return -1;
}
@@ -174,9 +175,9 @@ do_tXz_in (const char *dir, char filter)
fp = popen (cmd, "w");
if (fp == NULL) {
err = errno;
- cancel_receive ();
+ r = cancel_receive ();
errno = err;
- reply_with_perror ("%s", cmd);
+ if (r != -2) reply_with_perror ("%s", cmd);
free (cmd);
return -1;
}
@@ -186,8 +187,8 @@ do_tXz_in (const char *dir, char filter)
r = receive_file (write_cb, &fd);
if (r == -1) { /* write error */
- cancel_receive ();
- reply_with_error ("write error on directory: %s", dir);
+ r = cancel_receive ();
+ if (r != -2) reply_with_error ("write error on directory: %s", dir);
pclose (fp);
return -1;
}
@@ -199,8 +200,9 @@ do_tXz_in (const char *dir, char filter)
if (pclose (fp) != 0) {
if (r == -1) /* if r == 0, file transfer ended already */
- cancel_receive ();
- reply_with_error ("tar subcommand failed on directory: %s", dir);
+ r = cancel_receive ();
+ if (r != -2)
+ reply_with_error ("tar subcommand failed on directory: %s", dir);
return -1;
}
diff --git a/daemon/upload.c b/daemon/upload.c
index d93a5ade..9a6c8731 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -47,18 +47,18 @@ do_upload (const char *filename)
if (!is_dev) CHROOT_OUT;
if (fd == -1) {
err = errno;
- cancel_receive ();
+ r = cancel_receive ();
errno = err;
- reply_with_perror ("%s", filename);
+ if (r != -2) reply_with_perror ("%s", filename);
return -1;
}
r = receive_file (write_cb, &fd);
if (r == -1) { /* write error */
err = errno;
- cancel_receive ();
+ r = cancel_receive ();
errno = err;
- reply_with_error ("write error: %s", filename);
+ if (r != -2) reply_with_error ("write error: %s", filename);
close (fd);
return -1;
}
@@ -71,9 +71,10 @@ do_upload (const char *filename)
if (close (fd) == -1) {
err = errno;
if (r == -1) /* if r == 0, file transfer ended already */
- cancel_receive ();
+ r = cancel_receive ();
errno = err;
- reply_with_perror ("close: %s", filename);
+ if (r != -2)
+ reply_with_perror ("close: %s", filename);
return -1;
}