+/* Test if option is supported by qemu command line (just by grepping
+ * the help text).
+ */
+static int
+qemu_supports (guestfs_h *g, const char *option)
+{
+ return g->qemu_help && strstr (g->qemu_help, option) != NULL;
+}
+
+static void
+finish_wait_ready (guestfs_h *g, void *vp)
+{
+ if (g->verbose)
+ fprintf (stderr, "finish_wait_ready called, %p, vp = %p\n", g, vp);
+
+ *((int *)vp) = 1;
+ g->main_loop->main_loop_quit (g->main_loop, g);
+}
+
+int
+guestfs_wait_ready (guestfs_h *g)
+{
+ int finished = 0, r;
+
+ if (g->state == READY) return 0;
+
+ if (g->state == BUSY) {
+ error (g, _("qemu has finished launching already"));
+ return -1;
+ }
+
+ if (g->state != LAUNCHING) {
+ error (g, _("qemu has not been launched yet"));
+ return -1;
+ }
+
+ g->launch_done_cb = finish_wait_ready;
+ g->launch_done_cb_data = &finished;
+ r = g->main_loop->main_loop_run (g->main_loop, g);
+ g->launch_done_cb = NULL;
+ g->launch_done_cb_data = NULL;
+
+ if (r == -1) return -1;
+
+ if (finished != 1) {
+ error (g, _("guestfs_wait_ready failed, see earlier error messages"));
+ return -1;
+ }
+
+ /* This is possible in some really strange situations, such as
+ * guestfsd starts up OK but then qemu immediately exits. Check for
+ * it because the caller is probably expecting to be able to send
+ * commands after this function returns.
+ */
+ if (g->state != READY) {
+ error (g, _("qemu launched and contacted daemon, but state != READY"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+guestfs_kill_subprocess (guestfs_h *g)
+{
+ if (g->state == CONFIG) {
+ error (g, _("no subprocess to kill"));
+ return -1;
+ }
+
+ if (g->verbose)
+ fprintf (stderr, "sending SIGTERM to process %d\n", g->pid);
+
+ kill (g->pid, SIGTERM);
+ if (g->recoverypid > 0) kill (g->recoverypid, 9);
+
+ return 0;
+}
+
+/* Access current state. */
+int
+guestfs_is_config (guestfs_h *g)
+{
+ return g->state == CONFIG;
+}
+
+int
+guestfs_is_launching (guestfs_h *g)
+{
+ return g->state == LAUNCHING;
+}
+
+int
+guestfs_is_ready (guestfs_h *g)
+{
+ return g->state == READY;
+}
+
+int
+guestfs_is_busy (guestfs_h *g)
+{
+ return g->state == BUSY;
+}
+
+int
+guestfs_get_state (guestfs_h *g)
+{
+ return g->state;
+}
+
+int
+guestfs_set_ready (guestfs_h *g)
+{
+ if (g->state != BUSY) {
+ error (g, _("guestfs_set_ready: called when in state %d != BUSY"),
+ g->state);
+ return -1;
+ }
+ g->state = READY;
+ return 0;
+}
+
+int
+guestfs_set_busy (guestfs_h *g)
+{
+ if (g->state != READY) {
+ error (g, _("guestfs_set_busy: called when in state %d != READY"),
+ g->state);
+ return -1;
+ }
+ g->state = BUSY;
+ return 0;
+}
+
+int
+guestfs_end_busy (guestfs_h *g)
+{
+ switch (g->state)
+ {
+ case BUSY:
+ g->state = READY;
+ break;
+ case CONFIG:
+ case READY:
+ break;
+ case LAUNCHING:
+ case NO_HANDLE:
+ error (g, _("guestfs_end_busy: called when in state %d"), g->state);
+ return -1;
+ }