X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fguestfs.c;h=571205f209b2cb746f8c203cbc76f1251e3e6dee;hp=186c57081ca643e70c1e853359870f98baf67843;hb=7f2ac369f7747a033f5e84d8c7fb3aa131f25537;hpb=b5b87cdb764dc757295316878a7fd6e2ff01bec4 diff --git a/src/guestfs.c b/src/guestfs.c index 186c570..571205f 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -19,7 +19,6 @@ #include #define _BSD_SOURCE /* for mkdtemp, usleep */ -#define _GNU_SOURCE /* for vasprintf, GNU strerror_r, strchrnul */ #include #include @@ -58,15 +57,17 @@ #endif #include "guestfs.h" +#include "guestfs-internal-actions.h" #include "guestfs_protocol.h" +#include "ignore-value.h" #ifdef HAVE_GETTEXT #include "gettext.h" #define _(str) dgettext(PACKAGE, (str)) -#define N_(str) dgettext(PACKAGE, (str)) +//#define N_(str) dgettext(PACKAGE, (str)) #else #define _(str) str -#define N_(str) str +//#define N_(str) str #endif #define error guestfs_error @@ -74,7 +75,7 @@ #define safe_malloc guestfs_safe_malloc #define safe_realloc guestfs_safe_realloc #define safe_strdup guestfs_safe_strdup -#define safe_memdup guestfs_safe_memdup +//#define safe_memdup guestfs_safe_memdup static void default_error_cb (guestfs_h *g, void *data, const char *msg); static void stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, int watch, int fd, int events); @@ -177,6 +178,8 @@ struct guestfs_h int memsize; /* Size of RAM (megabytes). */ + int selinux; /* selinux enabled? */ + char *last_error; /* Callbacks. */ @@ -199,9 +202,9 @@ struct guestfs_h /* Messages sent and received from the daemon. */ char *msg_in; - int msg_in_size, msg_in_allocated; + unsigned int msg_in_size, msg_in_allocated; char *msg_out; - int msg_out_size, msg_out_pos; + unsigned int msg_out_size, msg_out_pos; int msg_next_serial; }; @@ -345,6 +348,10 @@ guestfs_close (guestfs_h *g) g->fd[1] = -1; g->sock = -1; + /* Wait for subprocess(es) to exit. */ + waitpid (g->pid, NULL, 0); + if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); + /* Remove tmpfiles. */ if (g->tmpdir) { snprintf (filename, sizeof filename, "%s/sock", g->tmpdir); @@ -537,8 +544,9 @@ guestfs_safe_memdup (guestfs_h *g, void *ptr, size_t size) } static int -xwrite (int fd, const void *buf, size_t len) +xwrite (int fd, const void *v_buf, size_t len) { + const char *buf = v_buf; int r; while (len > 0) { @@ -554,8 +562,9 @@ xwrite (int fd, const void *buf, size_t len) } static int -xread (int fd, void *buf, size_t len) +xread (int fd, void *v_buf, size_t len) { + char *buf = v_buf; int r; while (len > 0) { @@ -600,33 +609,33 @@ guestfs_get_error_handler (guestfs_h *g, void **data_rtn) } int -guestfs_set_verbose (guestfs_h *g, int v) +guestfs__set_verbose (guestfs_h *g, int v) { g->verbose = !!v; return 0; } int -guestfs_get_verbose (guestfs_h *g) +guestfs__get_verbose (guestfs_h *g) { return g->verbose; } int -guestfs_set_autosync (guestfs_h *g, int a) +guestfs__set_autosync (guestfs_h *g, int a) { g->autosync = !!a; return 0; } int -guestfs_get_autosync (guestfs_h *g) +guestfs__get_autosync (guestfs_h *g) { return g->autosync; } int -guestfs_set_path (guestfs_h *g, const char *path) +guestfs__set_path (guestfs_h *g, const char *path) { free (g->path); g->path = NULL; @@ -638,13 +647,13 @@ guestfs_set_path (guestfs_h *g, const char *path) } const char * -guestfs_get_path (guestfs_h *g) +guestfs__get_path (guestfs_h *g) { return g->path; } int -guestfs_set_qemu (guestfs_h *g, const char *qemu) +guestfs__set_qemu (guestfs_h *g, const char *qemu) { free (g->qemu); g->qemu = NULL; @@ -654,13 +663,13 @@ guestfs_set_qemu (guestfs_h *g, const char *qemu) } const char * -guestfs_get_qemu (guestfs_h *g) +guestfs__get_qemu (guestfs_h *g) { return g->qemu; } int -guestfs_set_append (guestfs_h *g, const char *append) +guestfs__set_append (guestfs_h *g, const char *append) { free (g->append); g->append = NULL; @@ -670,26 +679,39 @@ guestfs_set_append (guestfs_h *g, const char *append) } const char * -guestfs_get_append (guestfs_h *g) +guestfs__get_append (guestfs_h *g) { return g->append; } int -guestfs_set_memsize (guestfs_h *g, int memsize) +guestfs__set_memsize (guestfs_h *g, int memsize) { g->memsize = memsize; return 0; } int -guestfs_get_memsize (guestfs_h *g) +guestfs__get_memsize (guestfs_h *g) { return g->memsize; } int -guestfs_get_pid (guestfs_h *g) +guestfs__set_selinux (guestfs_h *g, int selinux) +{ + g->selinux = selinux; + return 0; +} + +int +guestfs__get_selinux (guestfs_h *g) +{ + return g->selinux; +} + +int +guestfs__get_pid (guestfs_h *g) { if (g->pid > 0) return g->pid; @@ -700,7 +722,7 @@ guestfs_get_pid (guestfs_h *g) } struct guestfs_version * -guestfs_version (guestfs_h *g) +guestfs__version (guestfs_h *g) { struct guestfs_version *r; @@ -742,8 +764,8 @@ add_cmdline (guestfs_h *g, const char *str) } int -guestfs_config (guestfs_h *g, - const char *qemu_param, const char *qemu_value) +guestfs__config (guestfs_h *g, + const char *qemu_param, const char *qemu_value) { if (qemu_param[0] != '-') { error (g, _("guestfs_config: parameter must begin with '-' character")); @@ -774,7 +796,7 @@ guestfs_config (guestfs_h *g, } int -guestfs_add_drive (guestfs_h *g, const char *filename) +guestfs__add_drive (guestfs_h *g, const char *filename) { size_t len = strlen (filename) + 64; char buf[len]; @@ -784,19 +806,36 @@ guestfs_add_drive (guestfs_h *g, const char *filename) return -1; } - if (access (filename, F_OK) == -1) { - perrorf (g, "%s", filename); - return -1; + /* cache=off improves reliability in the event of a host crash. + * + * However this option causes qemu to try to open the file with + * O_DIRECT. This fails on some filesystem types (notably tmpfs). + * So we check if we can open the file with or without O_DIRECT, + * and use cache=off (or not) accordingly. + * + * This test also checks for the presence of the file, which + * is a documented semantic of this interface. + */ + int fd = open (filename, O_RDONLY|O_DIRECT); + if (fd >= 0) { + close (fd); + snprintf (buf, len, "file=%s,cache=off,if=" DRIVE_IF, filename); + } else { + fd = open (filename, O_RDONLY); + if (fd >= 0) { + close (fd); + snprintf (buf, len, "file=%s,if=" DRIVE_IF, filename); + } else { + perrorf (g, "%s", filename); + return -1; + } } - /* cache=off improves reliability in the event of a host crash. */ - snprintf (buf, len, "file=%s,cache=off,if=%s", filename, DRIVE_IF); - return guestfs_config (g, "-drive", buf); } int -guestfs_add_drive_ro (guestfs_h *g, const char *filename) +guestfs__add_drive_ro (guestfs_h *g, const char *filename) { size_t len = strlen (filename) + 64; char buf[len]; @@ -817,7 +856,7 @@ guestfs_add_drive_ro (guestfs_h *g, const char *filename) } int -guestfs_add_cdrom (guestfs_h *g, const char *filename) +guestfs__add_cdrom (guestfs_h *g, const char *filename) { if (strchr (filename, ',') != NULL) { error (g, _("filename cannot contain ',' (comma) character")); @@ -866,6 +905,7 @@ dir_contains_files (const char *dir, ...) static int build_supermin_appliance (guestfs_h *g, const char *path, char **kernel, char **initrd); static int test_qemu (guestfs_h *g); static int qemu_supports (guestfs_h *g, const char *option); +static void print_cmdline (guestfs_h *g); static const char *kernel_name = "vmlinuz." REPO "." host_cpu; static const char *initrd_name = "initramfs." REPO "." host_cpu ".img"; @@ -875,11 +915,11 @@ static const char *supermin_hostfiles_name = "initramfs." REPO "." host_cpu ".supermin.hostfiles"; int -guestfs_launch (guestfs_h *g) +guestfs__launch (guestfs_h *g) { const char *tmpdir; char dir_template[PATH_MAX]; - int r, i, pmore; + int r, pmore; size_t len; int wfd[2], rfd[2]; int tries; @@ -1046,15 +1086,19 @@ guestfs_launch (guestfs_h *g) "udevtimeout=300 " /* good for very slow systems (RHBZ#480319) */ \ "noapic " /* workaround for RHBZ#502058 - ok if not SMP */ \ "acpi=off " /* we don't need ACPI, turn it off */ \ - "cgroup_disable=memory " /* saves us about 5 MB of RAM */ \ - "selinux=0 " /* SELinux is messed up if there's no policy */ + "cgroup_disable=memory " /* saves us about 5 MB of RAM */ /* Linux kernel command line. */ snprintf (append, sizeof append, - LINUX_CMDLINE "guestfs=%s:%d%s%s%s", + LINUX_CMDLINE + "guestfs=%s:%d " + "%s" /* (selinux) */ + "%s" /* (verbose) */ + "%s", /* (append) */ VMCHANNEL_ADDR, VMCHANNEL_PORT, - g->verbose ? " guestfs_verbose=1" : "", - g->append ? " " : "", g->append ? g->append : ""); + g->selinux ? "selinux=1 enforcing=0 " : "selinux=0 ", + g->verbose ? "guestfs_verbose=1 " : " ", + g->append ? g->append : ""); snprintf (memsize_str, sizeof memsize_str, "%d", g->memsize); @@ -1116,20 +1160,23 @@ guestfs_launch (guestfs_h *g) incr_cmdline_size (g); g->cmdline[g->cmdline_size-1] = NULL; - if (g->verbose) { - fprintf (stderr, "%s", g->qemu); - for (i = 0; g->cmdline[i]; ++i) - fprintf (stderr, " %s", g->cmdline[i]); - fprintf (stderr, "\n"); - } + if (g->verbose) + print_cmdline (g); /* Set up stdin, stdout. */ close (0); close (1); close (wfd[1]); close (rfd[0]); - dup (wfd[0]); - dup (rfd[1]); + + if (dup (wfd[0]) == -1) { + dup_failed: + perror ("dup failed"); + _exit (1); + } + if (dup (rfd[1]) == -1) + goto dup_failed; + close (wfd[0]); close (rfd[1]); @@ -1301,6 +1348,33 @@ guestfs_launch (guestfs_h *g) return -1; } +/* This function is used to print the qemu command line before it gets + * executed, when in verbose mode. + */ +static void +print_cmdline (guestfs_h *g) +{ + int i = 0; + int needs_quote; + + while (g->cmdline[i]) { + if (g->cmdline[i][0] == '-') /* -option starts a new line */ + fprintf (stderr, " \\\n "); + + if (i > 0) fputc (' ', stderr); + + /* Does it need shell quoting? This only deals with simple cases. */ + needs_quote = strcspn (g->cmdline[i], " ") != strlen (g->cmdline[i]); + + if (needs_quote) fputc ('\'', stderr); + fprintf (stderr, "%s", g->cmdline[i]); + if (needs_quote) fputc ('\'', stderr); + i++; + } + + fputc ('\n', stderr); +} + /* This function does the hard work of building the supermin appliance * on the fly. 'path' is the directory containing the control files. * 'kernel' and 'initrd' are where we will return the names of the @@ -1433,7 +1507,7 @@ finish_wait_ready (guestfs_h *g, void *vp) } int -guestfs_wait_ready (guestfs_h *g) +guestfs__wait_ready (guestfs_h *g) { int finished = 0, r; @@ -1476,7 +1550,7 @@ guestfs_wait_ready (guestfs_h *g) } int -guestfs_kill_subprocess (guestfs_h *g) +guestfs__kill_subprocess (guestfs_h *g) { if (g->state == CONFIG) { error (g, _("no subprocess to kill")); @@ -1494,37 +1568,37 @@ guestfs_kill_subprocess (guestfs_h *g) /* Access current state. */ int -guestfs_is_config (guestfs_h *g) +guestfs__is_config (guestfs_h *g) { return g->state == CONFIG; } int -guestfs_is_launching (guestfs_h *g) +guestfs__is_launching (guestfs_h *g) { return g->state == LAUNCHING; } int -guestfs_is_ready (guestfs_h *g) +guestfs__is_ready (guestfs_h *g) { return g->state == READY; } int -guestfs_is_busy (guestfs_h *g) +guestfs__is_busy (guestfs_h *g) { return g->state == BUSY; } int -guestfs_get_state (guestfs_h *g) +guestfs__get_state (guestfs_h *g) { return g->state; } int -guestfs_set_ready (guestfs_h *g) +guestfs__set_ready (guestfs_h *g) { if (g->state != BUSY) { error (g, _("guestfs_set_ready: called when in state %d != BUSY"), @@ -1536,7 +1610,7 @@ guestfs_set_ready (guestfs_h *g) } int -guestfs_set_busy (guestfs_h *g) +guestfs__set_busy (guestfs_h *g) { if (g->state != READY) { error (g, _("guestfs_set_busy: called when in state %d != READY"), @@ -1548,7 +1622,7 @@ guestfs_set_busy (guestfs_h *g) } int -guestfs_end_busy (guestfs_h *g) +guestfs__end_busy (guestfs_h *g) { switch (g->state) { @@ -1558,8 +1632,10 @@ guestfs_end_busy (guestfs_h *g) case CONFIG: case READY: break; + case LAUNCHING: case NO_HANDLE: + default: error (g, _("guestfs_end_busy: called when in state %d"), g->state); return -1; } @@ -1637,7 +1713,7 @@ stdout_event (struct guestfs_main_loop *ml, guestfs_h *g, void *data, /* In verbose mode, copy all log messages to stderr. */ if (g->verbose) - write (2, buf, n); + ignore_value (write (STDERR_FILENO, buf, n)); /* It's an actual log message, send it upwards if anyone is listening. */ if (g->log_message_cb) @@ -2338,7 +2414,7 @@ guestfs__receive_file_sync (guestfs_h *g, const char *filename) return -1; } - while ((r = receive_file_data_sync (g, NULL, NULL)) > 0) + while (receive_file_data_sync (g, NULL, NULL) > 0) ; /* just discard it */ return -1; @@ -2447,7 +2523,7 @@ receive_file_data_sync (guestfs_h *g, void **buf, size_t *len_r) if (buf) { *buf = safe_realloc (g, *buf, len + ctx.chunks[i].data.data_len); - memcpy (*buf+len, ctx.chunks[i].data.data_val, + memcpy (((char *)*buf)+len, ctx.chunks[i].data.data_val, ctx.chunks[i].data.data_len); } len += ctx.chunks[i].data.data_len; @@ -2553,6 +2629,7 @@ select_remove_handle (guestfs_main_loop *mlv, guestfs_h *g, int fd) } static int +__attribute__((noreturn)) select_add_timeout (guestfs_main_loop *mlv, guestfs_h *g, int interval, guestfs_handle_timeout_cb cb, void *data) { @@ -2562,6 +2639,7 @@ select_add_timeout (guestfs_main_loop *mlv, guestfs_h *g, int interval, } static int +__attribute__((noreturn)) select_remove_timeout (guestfs_main_loop *mlv, guestfs_h *g, int timer) { //struct select_main_loop *ml = (struct select_main_loop *) mlv;