>From 680d532bf92d1d3cbc208ad94d6133b69bcbb54a Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Sat, 31 Jul 2010 14:35:32 +0100 Subject: [PATCH] Enable coredumps to be captured from the appliance (RHBZ#619334). --- daemon/guestfsd.c | 45 ++++++++++++++++++++++++++++++ fish/guestfish.pod | 6 ++++ src/generator.ml | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ src/guestfs-internal.h | 1 + src/guestfs.c | 29 +++++++++++++++++++ src/guestfs.pod | 6 ++++ src/launch.c | 8 +++++ 7 files changed, 167 insertions(+), 0 deletions(-) diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index 49aca08..91d59cc 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #ifdef HAVE_PRINTF_H # include @@ -211,6 +213,49 @@ main (int argc, char *argv[]) } #ifndef WIN32 + /* Enable coredumps. */ + if (cmdline) { + char *p = strstr (cmdline, "guestfs_coredump="); + if (p) { + p += 17; + size_t len = strcspn (p, " \t\n"); + char *coredump = strndup (p, len); + if (!coredump) { + perror ("strndup"); + exit (EXIT_FAILURE); + } + +#define CORE_PATTERN "/proc/sys/kernel/core_pattern" + int fd = open (CORE_PATTERN, O_WRONLY); + if (fd == -1) { + perror ("open: " CORE_PATTERN); + exit (EXIT_FAILURE); + } + if (write (fd, coredump, len) < (ssize_t) len) { + perror ("write: " CORE_PATTERN); + exit (EXIT_FAILURE); + } + if (close (fd) == -1) { + perror ("close: " CORE_PATTERN); + exit (EXIT_FAILURE); + } + + struct rlimit limit = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY + }; + if (setrlimit (RLIMIT_CORE, &limit) == -1) { + perror ("setrlimit (RLIMIT_CORE)"); + exit (EXIT_FAILURE); + } + + if (verbose) + printf ("coredumps enabled to '%s'\n", coredump); + } + } +#endif /* !WIN32 */ + +#ifndef WIN32 /* Make sure SIGPIPE doesn't kill us. */ struct sigaction sa; memset (&sa, 0, sizeof sa); diff --git a/fish/guestfish.pod b/fish/guestfish.pod index bfcec5c..9aa01df 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -875,6 +875,12 @@ home directory can be used. See L. Pass additional options to the guest kernel. +=item LIBGUESTFS_COREDUMP + +Capture coredump(s) which happen inside the libguestfs appliance. +For further details of this option, see +L. + =item LIBGUESTFS_DEBUG Set C to enable verbose messages. This has the diff --git a/src/generator.ml b/src/generator.ml index 52e7aba..fea771a 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -940,6 +940,78 @@ to specify the QEMU interface emulation to use at run time."); This is the same as C but it allows you to specify the QEMU interface emulation to use at run time."); + ("set_coredump", (RErr, [OptString "coredump"]), -1, [FishAlias "coredump"], + [], + "capture coredump to file or block device", + "\ +This option can be used to debug coredumps in the libguestfs +appliance, in the daemon or in auxiliary programs that it +runs. Set this to a string which is written verbatim to +C in the appliance during launch. +Set this to NULL to disable coredumps. + +Useful values for this setting include: + +=over 4 + +=item C + +Coredump(s) are written to the root directory of the mounted +guest disk. The name of the core file includes the current +time (seconds since the epoch), PID, and the name of the +executable. + +Note that the prefix C is an implementation detail +of the current appliance and may change in future. + +This requires that a guest disk is mounted and writable +at the time that the coredump is generated, otherwise +the coredump will be discarded. + +=back + +The following are I useful values for this setting: + +=over 4 + +=item C + +The Linux kernel explicitly disallows writing coredumps to +non-regular files. Therefore using a coredump capture device +like this does not work. + +=item C + +=item C + +If you use paths or filenames like these, then coredump(s) are written +to the root disk in the appliance. This is not very useful, because +the root disk is a ramdisk which is forgotten when the appliance +shuts down. + +=back + +The default is C unless overridden by setting the +C environment variable. + +Note that you must set this before calling C, +otherwise it has no effect. + +This debugging feature is not part of the ABI and may be +changed or removed in a future release."); + + ("get_coredump", (RConstOptString "coredump", []), -1, [], + (* This cannot be tested with the current framework. The + * function can return NULL in normal operations, which the + * test framework interprets as an error. + *) + [], + "get the coredump debugging setting", + "\ +Return the coredump debugging setting. + +See C."); + ] (* daemon_functions are any functions which cause some action diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 12ca0ec..9f90904 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -110,6 +110,7 @@ struct guestfs_h char *path; /* Path to kernel, initrd. */ char *qemu; /* Qemu binary. */ char *append; /* Append to kernel command line. */ + char *coredump; /* Coredump path. */ int memsize; /* Size of RAM (megabytes). */ diff --git a/src/guestfs.c b/src/guestfs.c index c54462d..244f2c6 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -509,6 +509,35 @@ guestfs__get_append (guestfs_h *g) } int +guestfs__set_coredump (guestfs_h *g, const char *coredump) +{ + if (coredump != NULL) { + /* Because we pass this in the kernel command line, it will + * currently fail if it contains any whitespace. We ought to fix + * this by escaping spaces and unescaping them in the appliance. XXX + */ + size_t i; + for (i = 0; i < strlen (coredump); ++i) + if (c_isspace (coredump[i])) { + error (g, "coredump parameter must not contain whitespace"); + return -1; + } + } + + free (g->coredump); + g->coredump = NULL; + + g->coredump = coredump ? safe_strdup (g, coredump) : NULL; + return 0; +} + +const char * +guestfs__get_coredump (guestfs_h *g) +{ + return g->coredump; +} + +int guestfs__set_memsize (guestfs_h *g, int memsize) { g->memsize = memsize; diff --git a/src/guestfs.pod b/src/guestfs.pod index 5a2e7a5..0749da7 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -1478,6 +1478,12 @@ time. Pass additional options to the guest kernel. +=item LIBGUESTFS_COREDUMP + +Capture coredump(s) which happen inside the libguestfs appliance. +For further details of this option, see +L. + =item LIBGUESTFS_DEBUG Set C to enable verbose messages. This diff --git a/src/launch.c b/src/launch.c index 0d7a3f3..5d3c236 100644 --- a/src/launch.c +++ b/src/launch.c @@ -598,6 +598,12 @@ guestfs__launch (guestfs_h *g) add_cmdline (g, "-net"); add_cmdline (g, "nic,model=" NET_IF ",vlan=0"); + /* Coredump parameter for Linux command line. */ + size_t len = g->coredump ? 32 + strlen (g->coredump) : 0; + char coredump[len]; + if (g->coredump) + snprintf (coredump, len, "guestfs_coredump=%s", g->coredump); + #define LINUX_CMDLINE \ "panic=1 " /* force kernel to panic if daemon exits */ \ "console=ttyS0 " /* serial console */ \ @@ -613,11 +619,13 @@ guestfs__launch (guestfs_h *g) "%s " /* (selinux) */ "%s " /* (vmchannel) */ "%s " /* (verbose) */ + "%s " /* (coredump) */ "TERM=%s " /* (TERM environment variable) */ "%s", /* (append) */ g->selinux ? "selinux=1 enforcing=0" : "selinux=0", vmchannel ? vmchannel : "", g->verbose ? "guestfs_verbose=1" : "", + g->coredump ? coredump : "", getenv ("TERM") ? : "linux", g->append ? g->append : ""); -- 1.7.1