Richard W.M. Jones
2014-May-03 16:01 UTC
[Libguestfs] [PATCH 0/1] New API: cpio-out converts a directory to cpio format.
After developing this API, I realized I didn't need it for what I was trying to do :-/ However it might still be a handy API to have, so I'm posting it. Rich.
Richard W.M. Jones
2014-May-03 16:01 UTC
[Libguestfs] [PATCH] New API: cpio-out converts a directory to cpio format.
This is useful for generating Linux initramfses from other types of filesystems. For example: guestfish --ro -a disk.img -i cpio-out / - | gzip -9 > initrd.img --- daemon/Makefile.am | 1 + daemon/cpio.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ generator/actions.ml | 28 ++++++++++++ gobject/Makefile.inc | 2 + po/POTFILES | 2 + src/MAX_PROC_NR | 2 +- 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 daemon/cpio.c diff --git a/daemon/Makefile.am b/daemon/Makefile.am index b18f9ff..8ccf322 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -93,6 +93,7 @@ guestfsd_SOURCES = \ command.c \ compress.c \ copy.c \ + cpio.c \ cpmv.c \ daemon.h \ dd.c \ diff --git a/daemon/cpio.c b/daemon/cpio.c new file mode 100644 index 0000000..e33e47b --- /dev/null +++ b/daemon/cpio.c @@ -0,0 +1,124 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "read-file.h" + +#include "guestfs_protocol.h" +#include "daemon.h" +#include "actions.h" +#include "optgroups.h" + +GUESTFSD_EXT_CMD(str_cpio, cpio); + +/* Has one FileOut parameter. */ +/* Takes optional arguments, consult optargs_bitmask. */ +int +do_cpio_out (const char *dir, const char *format) +{ + CLEANUP_FREE char *buf = NULL; + struct stat statbuf; + int r; + FILE *fp; + CLEANUP_FREE char *cmd = NULL; + char buffer[GUESTFS_MAX_CHUNK_SIZE]; + + /* Check the filename exists and is a directory (RHBZ#908322). */ + buf = sysroot_path (dir); + if (buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + if (stat (buf, &statbuf) == -1) { + reply_with_perror ("stat: %s", dir); + return -1; + } + + if (! S_ISDIR (statbuf.st_mode)) { + reply_with_error ("%s: not a directory", dir); + return -1; + } + + /* Check the format is one of the permitted ones. */ + if ((optargs_bitmask & GUESTFS_CPIO_OUT_FORMAT_BITMASK)) { + if (STRNEQ (format, "newc") && STRNEQ (format, "crc")) { + reply_with_error ("%s: format must be 'newc' or 'crc'", format); + return -1; + } + } + else + format = "newc"; + + if (asprintf_nowarn (&cmd, "cd %Q && find -print0 | %s -0 -o -H %s --quiet", + buf, + str_cpio, + format) == -1) { + reply_with_perror ("asprintf"); + return -1; + } + + if (verbose) + fprintf (stderr, "%s\n", cmd); + + 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 (buffer, 1, sizeof buffer, fp)) > 0) { + if (send_file_write (buffer, r) < 0) { + pclose (fp); + return -1; + } + } + + if (ferror (fp)) { + fprintf (stderr, "fread: %s: %m\n", dir); + send_file_end (1); /* Cancel. */ + pclose (fp); + return -1; + } + + if (pclose (fp) != 0) { + fprintf (stderr, "pclose: %s: %m\n", dir); + send_file_end (1); /* Cancel. */ + return -1; + } + + if (send_file_end (0)) /* Normal end of file. */ + return -1; + + return 0; +} diff --git a/generator/actions.ml b/generator/actions.ml index ef3f17e..aecc63b 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -11882,6 +11882,34 @@ blocks of zero bytes when read the next time. If it returns false, then it may be that discarded blocks are read as stale or random data." }; + { defaults with + name = "cpio_out"; + style = RErr, [String "directory"; FileOut "cpiofile"], [OString "format"]; + proc_nr = Some 419; + cancellable = true; + shortdesc = "pack directory into cpio file"; + longdesc = "\ +This command packs the contents of C<directory> and downloads +it to local file C<cpiofile>. + +The optional C<format> parameter can be used to select the format. +Only the following formats are currently permitted: + +=over 4 + +=item C<newc> + +New (SVR4) portable format. This format happens to be compatible +with the cpio-like format used by the Linux kernel for initramfs. + +This is the default format. + +=item C<crc> + +New (SVR4) portable format with a checksum. + +=back" }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index cfb6ed3..3b567a2 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -55,6 +55,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-copy_device_to_file.h \ include/guestfs-gobject/optargs-copy_file_to_device.h \ include/guestfs-gobject/optargs-copy_file_to_file.h \ + include/guestfs-gobject/optargs-cpio_out.h \ include/guestfs-gobject/optargs-disk_create.h \ include/guestfs-gobject/optargs-e2fsck.h \ include/guestfs-gobject/optargs-fstrim.h \ @@ -131,6 +132,7 @@ guestfs_gobject_sources= \ src/optargs-copy_device_to_file.c \ src/optargs-copy_file_to_device.c \ src/optargs-copy_file_to_file.c \ + src/optargs-cpio_out.c \ src/optargs-disk_create.c \ src/optargs-e2fsck.c \ src/optargs-fstrim.c \ diff --git a/po/POTFILES b/po/POTFILES index 0fac8fe..ac12815 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -27,6 +27,7 @@ daemon/cmp.c daemon/command.c daemon/compress.c daemon/copy.c +daemon/cpio.c daemon/cpmv.c daemon/dd.c daemon/debug.c @@ -174,6 +175,7 @@ gobject/src/optargs-copy_device_to_device.c gobject/src/optargs-copy_device_to_file.c gobject/src/optargs-copy_file_to_device.c gobject/src/optargs-copy_file_to_file.c +gobject/src/optargs-cpio_out.c gobject/src/optargs-disk_create.c gobject/src/optargs-e2fsck.c gobject/src/optargs-fstrim.c diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 29aae8e..7b53aa0 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -418 +419 -- 1.9.0