From e4fbe3e2cd130fa0b1b21a105729cd6ef32aac38 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Tue, 9 Feb 2010 12:26:22 +0000 Subject: [PATCH] New API call: initrd-cat to list a file from an initrd. --- daemon/initrd.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/MAX_PROC_NR | 2 +- src/generator.ml | 17 ++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) diff --git a/daemon/initrd.c b/daemon/initrd.c index 9c92fee..5e73d40 100644 --- a/daemon/initrd.c +++ b/daemon/initrd.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "../src/guestfs_protocol.h" #include "daemon.h" @@ -79,3 +81,122 @@ do_initrd_list (const char *path) return filenames; } + +char * +do_initrd_cat (const char *path, const char *filename, size_t *size_r) +{ + char tmpdir[] = "/tmp/initrd-cat-XXXXXX"; + if (mkdtemp (tmpdir) == NULL) { + reply_with_perror ("mkdtemp"); + return NULL; + } + + /* "zcat /sysroot/ | cpio --quiet -id file", but paths must be quoted */ + char *cmd; + if (asprintf_nowarn (&cmd, "cd %Q && zcat %R | cpio --quiet -id %Q", + tmpdir, path, filename) == -1) { + reply_with_perror ("asprintf"); + rmdir (tmpdir); + return NULL; + } + + /* Extract file into temporary directory. This may create subdirs. + * It's also possible that this doesn't create anything at all + * (eg. if the named file does not exist in the cpio archive) -- + * cpio is silent in this case. + */ + int r = system (cmd); + if (r == -1) { + reply_with_perror ("command failed: %s", cmd); + rmdir (tmpdir); + return NULL; + } + if (WEXITSTATUS (r) != 0) { + reply_with_perror ("command failed with return code %d", + WEXITSTATUS (r)); + rmdir (tmpdir); + return NULL; + } + + /* See if we got a file. */ + char fullpath[PATH_MAX]; + snprintf (fullpath, sizeof fullpath, "%s/%s", tmpdir, filename); + + struct stat statbuf; + int fd; + + fd = open (fullpath, O_RDONLY); + if (fd == -1) { + reply_with_perror ("open: %s:%s", path, filename); + rmdir (tmpdir); + return NULL; + } + + /* From this point, we know the file exists, so we require full + * cleanup. + */ + char *ret = NULL; + + if (fstat (fd, &statbuf) == -1) { + reply_with_perror ("fstat: %s:%s", path, filename); + goto cleanup; + } + + *size_r = statbuf.st_size; + /* The actual limit on messages is smaller than this. This + * check just limits the amount of memory we'll try and allocate + * here. If the message is larger than the real limit, that will + * be caught later when we try to serialize the message. + */ + if (*size_r >= GUESTFS_MESSAGE_MAX) { + reply_with_error ("initrd_cat: %s:%s: file is too large for the protocol", + path, filename); + goto cleanup; + } + + ret = malloc (*size_r); + if (ret == NULL) { + reply_with_perror ("malloc"); + goto cleanup; + } + + if (xread (fd, ret, *size_r) == -1) { + reply_with_perror ("read: %s:%s", path, filename); + free (ret); + ret = NULL; + goto cleanup; + } + + if (close (fd) == -1) { + reply_with_perror ("close: %s:%s", path, filename); + free (ret); + ret = NULL; + goto cleanup; + } + fd = -1; + + cleanup: + if (fd >= 0) + close (fd); + + /* Remove the file. */ + if (unlink (fullpath) == -1) { + fprintf (stderr, "unlink: "); + perror (fullpath); + /* non-fatal */ + } + + /* Remove the directories up to and including the temp directory. */ + do { + char *p = strrchr (fullpath, '/'); + if (!p) break; + *p = '\0'; + if (rmdir (fullpath) == -1) { + fprintf (stderr, "rmdir: "); + perror (fullpath); + /* non-fatal */ + } + } while (STRNEQ (fullpath, tmpdir)); + + return ret; +} diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 3d4c7bf..7b47338 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -220 +221 diff --git a/src/generator.ml b/src/generator.ml index 6de2c7f..b4bbf1e 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -4224,6 +4224,23 @@ Rename a logical volume C with the new name C."); "\ Rename a volume group C with the new name C."); + ("initrd_cat", (RBufferOut "content", [Pathname "initrdpath"; String "filename"]), 221, [], + [InitISOFS, Always, TestOutputBuffer ( + [["initrd_cat"; "/initrd"; "known-4"]], "abc\ndef\nghi")], + "list the contents of a single file in an initrd", + "\ +This command unpacks the file C from the initrd file +called C. The filename must be given I the +initial C character. + +For example, in guestfish you could use the following command +to examine the boot script (usually called C) +contained in a Linux initrd or initramfs image: + + initrd-cat /boot/initrd-.img init + +See also C."); + ] let all_functions = non_daemon_functions @ daemon_functions -- 1.8.3.1