summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-20 15:54:22 +0100
committerRichard Jones <rjones@redhat.com>2009-04-20 15:54:22 +0100
commit0232e722826cfda0f6042da983f9eb871f24e946 (patch)
treee08a414ae15cc70f60ed6275231f9ae050a033fe /daemon
parent11350529fee2dbbcfda333bbe10d72f023dc2109 (diff)
downloadlibguestfs-0232e722826cfda0f6042da983f9eb871f24e946.tar.gz
libguestfs-0232e722826cfda0f6042da983f9eb871f24e946.tar.xz
libguestfs-0232e722826cfda0f6042da983f9eb871f24e946.zip
Added tar-in, tar-out, tgz-in, tgz-out commands.
Diffstat (limited to 'daemon')
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/actions.h4
-rw-r--r--daemon/stubs.c108
-rw-r--r--daemon/tar.c279
4 files changed, 392 insertions, 0 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 18866393..4f7ce24d 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -36,6 +36,7 @@ guestfsd_SOURCES = \
stat.c \
stubs.c \
sync.c \
+ tar.c \
tune2fs.c \
upload.c \
../src/guestfs_protocol.h \
diff --git a/daemon/actions.h b/daemon/actions.h
index cffd8efa..d55f4930 100644
--- a/daemon/actions.h
+++ b/daemon/actions.h
@@ -89,3 +89,7 @@ extern int do_blockdev_rereadpt (const char *device);
extern int do_upload (const char *remotefilename);
extern int do_download (const char *remotefilename);
extern char *do_checksum (const char *csumtype, const char *path);
+extern int do_tar_in (const char *directory);
+extern int do_tar_out (const char *directory);
+extern int do_tgz_in (const char *directory);
+extern int do_tgz_out (const char *directory);
diff --git a/daemon/stubs.c b/daemon/stubs.c
index 30394049..82016412 100644
--- a/daemon/stubs.c
+++ b/daemon/stubs.c
@@ -1661,6 +1661,102 @@ done:
xdr_free ((xdrproc_t) xdr_guestfs_checksum_args, (char *) &args);
}
+static void tar_in_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tar_in_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tar_in_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tar_in");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tar_in (directory);
+ if (r == -1)
+ /* do_tar_in has already called reply_with_error */
+ goto done;
+
+ reply (NULL, NULL);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tar_in_args, (char *) &args);
+}
+
+static void tar_out_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tar_out_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tar_out_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tar_out");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tar_out (directory);
+ if (r == -1)
+ /* do_tar_out has already called reply_with_error */
+ goto done;
+
+ /* do_tar_out has already sent a reply */
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tar_out_args, (char *) &args);
+}
+
+static void tgz_in_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tgz_in_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tgz_in_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tgz_in");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tgz_in (directory);
+ if (r == -1)
+ /* do_tgz_in has already called reply_with_error */
+ goto done;
+
+ reply (NULL, NULL);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tgz_in_args, (char *) &args);
+}
+
+static void tgz_out_stub (XDR *xdr_in)
+{
+ int r;
+ struct guestfs_tgz_out_args args;
+ const char *directory;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_tgz_out_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "tgz_out");
+ return;
+ }
+ directory = args.directory;
+
+ r = do_tgz_out (directory);
+ if (r == -1)
+ /* do_tgz_out has already called reply_with_error */
+ goto done;
+
+ /* do_tgz_out has already sent a reply */
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_tgz_out_args, (char *) &args);
+}
+
void dispatch_incoming_message (XDR *xdr_in)
{
switch (proc_nr) {
@@ -1868,6 +1964,18 @@ void dispatch_incoming_message (XDR *xdr_in)
case GUESTFS_PROC_CHECKSUM:
checksum_stub (xdr_in);
break;
+ case GUESTFS_PROC_TAR_IN:
+ tar_in_stub (xdr_in);
+ break;
+ case GUESTFS_PROC_TAR_OUT:
+ tar_out_stub (xdr_in);
+ break;
+ case GUESTFS_PROC_TGZ_IN:
+ tgz_in_stub (xdr_in);
+ break;
+ case GUESTFS_PROC_TGZ_OUT:
+ tgz_out_stub (xdr_in);
+ break;
default:
reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
}
diff --git a/daemon/tar.c b/daemon/tar.c
new file mode 100644
index 00000000..ecf919db
--- /dev/null
+++ b/daemon/tar.c
@@ -0,0 +1,279 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "../src/guestfs_protocol.h"
+#include "daemon.h"
+#include "actions.h"
+
+static int
+fwrite_cb (void *fp_ptr, const void *buf, int len)
+{
+ FILE *fp = *(FILE **)fp_ptr;
+ return fwrite (buf, len, 1, fp) == 1 ? 0 : -1;
+}
+
+/* Has one FileIn parameter. */
+int
+do_tar_in (const char *dir)
+{
+ int err, r, len;
+ FILE *fp;
+ char *cmd;
+
+ if (!root_mounted || dir[0] != '/') {
+ cancel_receive ();
+ reply_with_error ("tar-in: root must be mounted and path must be absolute");
+ return -1;
+ }
+
+ /* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -xf -");
+
+ fp = popen (cmd, "w");
+ if (fp == NULL) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("%s", cmd);
+ return -1;
+ }
+
+ r = receive_file (fwrite_cb, &fp);
+ if (r == -1) { /* write error */
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("write: %s", dir);
+ pclose (fp);
+ return -1;
+ }
+ if (r == -2) { /* cancellation from library */
+ pclose (fp);
+ /* Do NOT send any error. */
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("pclose: %s", dir);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Has one FileOut parameter. */
+int
+do_tar_out (const char *dir)
+{
+ int r, len;
+ FILE *fp;
+ char *cmd;
+ char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+ NEED_ROOT (-1);
+ ABS_PATH (dir, -1);
+
+ /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -cf - .");
+
+ fp = popen (cmd, "r");
+ if (fp == NULL) {
+ reply_with_perror ("%s", cmd);
+ return -1;
+ }
+
+ /* Now we must send the reply message, before the file contents. After
+ * this there is no opportunity in the protocol to send any error
+ * message back. Instead we can only cancel the transfer.
+ */
+ reply (NULL, NULL);
+
+ while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
+ if (send_file_write (buf, r) < 0) {
+ pclose (fp);
+ return -1;
+ }
+ }
+
+ if (r == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ pclose (fp);
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ return -1;
+ }
+
+ send_file_end (0); /* Normal end of file. */
+ return 0;
+}
+
+/* Has one FileIn parameter. */
+int
+do_tgz_in (const char *dir)
+{
+ int err, r, len;
+ FILE *fp;
+ char *cmd;
+
+ if (!root_mounted || dir[0] != '/') {
+ cancel_receive ();
+ reply_with_error ("tar-in: root must be mounted and path must be absolute");
+ return -1;
+ }
+
+ /* "tar -C /sysroot%s -zxf -" but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -zxf -");
+
+ fp = popen (cmd, "w");
+ if (fp == NULL) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("%s", cmd);
+ return -1;
+ }
+
+ r = receive_file (fwrite_cb, &fp);
+ if (r == -1) { /* write error */
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("write: %s", dir);
+ pclose (fp);
+ return -1;
+ }
+ if (r == -2) { /* cancellation from library */
+ pclose (fp);
+ /* Do NOT send any error. */
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ err = errno;
+ cancel_receive ();
+ errno = err;
+ reply_with_perror ("pclose: %s", dir);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Has one FileOut parameter. */
+int
+do_tgz_out (const char *dir)
+{
+ int r, len;
+ FILE *fp;
+ char *cmd;
+ char buf[GUESTFS_MAX_CHUNK_SIZE];
+
+ NEED_ROOT (-1);
+ ABS_PATH (dir, -1);
+
+ /* "tar -C /sysroot%s -zcf - ." but we have to quote the dir. */
+ len = 2 * strlen (dir) + 32;
+ cmd = malloc (len);
+ if (!cmd) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ strcpy (cmd, "tar -C /sysroot");
+ shell_quote (cmd+15, len-15, dir);
+ strcat (cmd, " -zcf - .");
+
+ fp = popen (cmd, "r");
+ if (fp == NULL) {
+ reply_with_perror ("%s", cmd);
+ return -1;
+ }
+
+ /* Now we must send the reply message, before the file contents. After
+ * this there is no opportunity in the protocol to send any error
+ * message back. Instead we can only cancel the transfer.
+ */
+ reply (NULL, NULL);
+
+ while ((r = fread (buf, 1, sizeof buf, fp)) > 0) {
+ if (send_file_write (buf, r) < 0) {
+ pclose (fp);
+ return -1;
+ }
+ }
+
+ if (r == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ pclose (fp);
+ return -1;
+ }
+
+ if (pclose (fp) == -1) {
+ perror (dir);
+ send_file_end (1); /* Cancel. */
+ return -1;
+ }
+
+ send_file_end (0); /* Normal end of file. */
+ return 0;
+}