/* libguestfs - the guestfsd daemon
- * Copyright (C) 2009 Red Hat Inc.
+ * 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
};
static char *debug_help (const char *subcmd, int argc, char *const *const argv);
+static char *debug_env (const char *subcmd, int argc, char *const *const argv);
static char *debug_fds (const char *subcmd, int argc, char *const *const argv);
+static char *debug_segv (const char *subcmd, int argc, char *const *const argv);
static char *debug_sh (const char *subcmd, int argc, char *const *const argv);
static struct cmd cmds[] = {
{ "help", debug_help },
+ { "env", debug_env },
{ "fds", debug_fds },
+ { "segv", debug_segv },
{ "sh", debug_sh },
{ NULL, NULL }
};
#endif
char *
-do_debug (const char *subcmd, char *const *const argv)
+do_debug (char *subcmd, char **argv)
{
#if ENABLE_DEBUG_COMMAND
int argc, i;
debug_fds (const char *subcmd, int argc, char *const *const argv)
{
int r;
- char *out = NULL;
+ char *out;
+ size_t size;
+ FILE *fp;
DIR *dir;
struct dirent *d;
char fname[256], link[256];
struct stat statbuf;
+ fp = open_memstream (&out, &size);
+ if (!fp) {
+ reply_with_perror ("open_memstream");
+ return NULL;
+ }
+
dir = opendir ("/proc/self/fd");
if (!dir) {
reply_with_perror ("opendir: /proc/self/fd");
+ fclose (fp);
return NULL;
}
r = lstat (fname, &statbuf);
if (r == -1) {
reply_with_perror ("stat: %s", fname);
+ fclose (fp);
free (out);
closedir (dir);
return NULL;
r = readlink (fname, link, sizeof link - 1);
if (r == -1) {
reply_with_perror ("readline: %s", fname);
+ fclose (fp);
free (out);
closedir (dir);
return NULL;
}
link[r] = '\0';
- r = catprintf (&out, "%2s %s\n", d->d_name, link);
+ fprintf (fp, "%2s %s\n", d->d_name, link);
} else
- r = catprintf (&out, "%2s 0%o\n", d->d_name, statbuf.st_mode);
-
- if (r == -1) {
- reply_with_perror ("catprintf");
- free (out);
- closedir (dir);
- return NULL;
- }
+ fprintf (fp, "%2s 0%o\n", d->d_name, statbuf.st_mode);
}
+ fclose (fp);
+
if (closedir (dir) == -1) {
reply_with_perror ("closedir");
free (out);
return out;
}
-/* Run an arbitrary shell command. */
+/* Force a segfault in the daemon. */
+static char *
+debug_segv (const char *subcmd, int argc, char *const *const argv)
+{
+ *(int*)0 = 0;
+ return NULL;
+}
+
+/* Run an arbitrary shell command using /bin/sh from the appliance.
+ *
+ * Note this is somewhat different from the ordinary guestfs_sh command
+ * because it's not using the guest shell, and is not chrooted.
+ *
+ * Also we ignore any errors and you can see the full output if you
+ * add 2>&1 to the end of the command string.
+ */
static char *
debug_sh (const char *subcmd, int argc, char *const *const argv)
{
+ char *cmd;
+ int len, i, j;
+ char *out;
+
+ if (argc < 1) {
+ reply_with_error ("debug: sh: expecting a command to run");
+ return NULL;
+ }
+
+ /* guestfish splits the parameter(s) into a list of strings,
+ * and we have to reassemble them here. Not ideal. XXX
+ */
+ for (i = len = 0; i < argc; ++i)
+ len += strlen (argv[i]) + 1;
+ cmd = malloc (len);
+ if (!cmd) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+ for (i = j = 0; i < argc; ++i) {
+ len = strlen (argv[i]);
+ memcpy (&cmd[j], argv[i], len);
+ j += len;
+ cmd[j] = ' ';
+ j++;
+ }
+ cmd[j-1] = '\0';
+
+ command (&out, NULL, "/bin/sh", "-c", cmd, NULL);
+ free (cmd);
+ return out;
+}
+
+/* Print the environment that commands get (by running external printenv). */
+static char *
+debug_env (const char *subcmd, int argc, char *const *const argv)
+{
int r;
char *out, *err;
- r = commandv (&out, &err, argv);
+ r = command (&out, &err, "printenv", NULL);
if (r == -1) {
- reply_with_error ("ps: %s", err);
+ reply_with_error ("printenv: %s", err);
free (out);
free (err);
return NULL;