Exemple #1
0
/**
 * This is called if we detect EOF, ie. qemu died.
 */
static void
child_cleanup (guestfs_h *g)
{
  debug (g, "child_cleanup: %p: child process died", g);

  g->backend_ops->shutdown (g, g->backend_data, 0);
  if (g->conn) {
    g->conn->ops->free_connection (g, g->conn);
    g->conn = NULL;
  }
  memset (&g->launch_t, 0, sizeof g->launch_t);
  guestfs_int_free_drives (g);
  g->state = CONFIG;
  guestfs_int_call_callbacks_void (g, GUESTFS_EVENT_SUBPROCESS_QUIT);
}
Exemple #2
0
void
guestfs_close (guestfs_h *g)
{
  struct hv_param *hp, *hp_next;
  guestfs_h **gg;

  if (g->state == NO_HANDLE) {
    /* Not safe to call ANY callbacks here, so ... */
    fprintf (stderr, _("guestfs_close: called twice on the same handle\n"));
    return;
  }

  /* Remove the handle from the handles list. */
  if (g->close_on_exit) {
    gl_lock_lock (handles_lock);
    for (gg = &handles; *gg != g; gg = &(*gg)->next)
      ;
    *gg = g->next;
    gl_lock_unlock (handles_lock);
  }

  if (g->trace) {
    const char trace_msg[] = "close";

    guestfs_int_call_callbacks_message (g, GUESTFS_EVENT_TRACE,
					trace_msg, strlen (trace_msg));
  }

  debug (g, "closing guestfs handle %p (state %d)", g, (int) g->state);

  if (g->state != CONFIG)
    shutdown_backend (g, 0);

  /* Run user close callbacks. */
  guestfs_int_call_callbacks_void (g, GUESTFS_EVENT_CLOSE);

  /* Test output file used by bindtests. */
  if (g->test_fp != NULL)
    fclose (g->test_fp);

  /* Remove temporary directory. */
  guestfs_int_remove_tmpdir (g);

  /* Mark the handle as dead and then free up all memory. */
  g->state = NO_HANDLE;

  free (g->events);
  g->nr_events = 0;
  g->events = NULL;

#if HAVE_FUSE
  guestfs_int_free_fuse (g);
#endif

  guestfs_int_free_inspect_info (g);
  guestfs_int_free_drives (g);

  for (hp = g->hv_params; hp; hp = hp_next) {
    free (hp->hv_param);
    free (hp->hv_value);
    hp_next = hp->next;
    free (hp);
  }

  while (g->error_cb_stack)
    guestfs_pop_error_handler (g);

  if (g->pda)
    hash_free (g->pda);
  free (g->tmpdir);
  free (g->env_tmpdir);
  free (g->int_tmpdir);
  free (g->int_cachedir);
  free (g->last_error);
  free (g->identifier);
  free (g->program);
  free (g->path);
  free (g->hv);
  free (g->backend);
  free (g->backend_data);
  guestfs_int_free_string_list (g->backend_settings);
  free (g->append);
  free (g);
}
Exemple #3
0
/**
 * This function reads a single message, file chunk, launch flag or
 * cancellation flag from the daemon.  If something was read, it
 * returns C<0>, otherwise C<-1>.
 *
 * Both C<size_rtn> and C<buf_rtn> must be passed by the caller as
 * non-NULL.
 *
 * C<*size_rtn> returns the size of the returned message or it may be
 * C<GUESTFS_LAUNCH_FLAG> or C<GUESTFS_CANCEL_FLAG>.
 *
 * C<*buf_rtn> is returned containing the message (if any) or will be
 * set to C<NULL>.  C<*buf_rtn> must be freed by the caller.
 *
 * This checks for EOF (appliance died) and passes that up through the
 * child_cleanup function above.
 *
 * Log message, progress messages are handled transparently here.
 */
static int
recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn)
{
  char lenbuf[4];
  ssize_t n;
  XDR xdr;
  size_t message_size;

  *size_rtn = 0;
  *buf_rtn = NULL;

  /* RHBZ#914931: Along some (rare) paths, we might have closed the
   * socket connection just before this function is called, so just
   * return an error if this happens.
   */
  if (!g->conn) {
    guestfs_int_unexpected_close_error (g);
    return -1;
  }

  /* Read the 4 byte size / flag. */
  n = g->conn->ops->read_data (g, g->conn, lenbuf, 4);
  if (n == -1)
    return -1;
  if (n == 0) {
    guestfs_int_unexpected_close_error (g);
    child_cleanup (g);
    return -1;
  }

  xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
  xdr_uint32_t (&xdr, size_rtn);
  xdr_destroy (&xdr);

  if (*size_rtn == GUESTFS_LAUNCH_FLAG) {
    if (g->state != LAUNCHING)
      error (g, _("received magic signature from guestfsd, but in state %d"),
             (int) g->state);
    else {
      g->state = READY;
      guestfs_int_call_callbacks_void (g, GUESTFS_EVENT_LAUNCH_DONE);
    }
    debug (g, "recv_from_daemon: received GUESTFS_LAUNCH_FLAG");
    return 0;
  }
  else if (*size_rtn == GUESTFS_CANCEL_FLAG) {
    debug (g, "recv_from_daemon: received GUESTFS_CANCEL_FLAG");
    return 0;
  }
  else if (*size_rtn == GUESTFS_PROGRESS_FLAG)
    /*FALLTHROUGH*/;
  else if (*size_rtn > GUESTFS_MESSAGE_MAX) {
    /* If this happens, it's pretty bad and we've probably lost
     * synchronization.
     */
    error (g, _("message length (%u) > maximum possible size (%d)"),
           (unsigned) *size_rtn, GUESTFS_MESSAGE_MAX);
    return -1;
  }

  /* Calculate the message size. */
  message_size =
    *size_rtn != GUESTFS_PROGRESS_FLAG ? *size_rtn : PROGRESS_MESSAGE_SIZE;

  /* Allocate the complete buffer, size now known. */
  *buf_rtn = safe_malloc (g, message_size);

  /* Read the message. */
  n = g->conn->ops->read_data (g, g->conn, *buf_rtn, message_size);
  if (n == -1) {
    free (*buf_rtn);
    *buf_rtn = NULL;
    return -1;
  }
  if (n == 0) {
    guestfs_int_unexpected_close_error (g);
    child_cleanup (g);
    free (*buf_rtn);
    *buf_rtn = NULL;
    return -1;
  }

  /* ... it's a normal message (not progress/launch/cancel) so display
   * it if we're debugging.
   */
#ifdef ENABLE_PACKET_DUMP
  if (g->verbose) {
    ssize_t i, j;

    for (i = 0; i < n; i += 16) {
      printf ("%04zx: ", i);
      for (j = i; j < MIN (i+16, n); ++j)
        printf ("%02x ", (*(unsigned char **)buf_rtn)[j]);
      for (; j < i+16; ++j)
        printf ("   ");
      printf ("|");
      for (j = i; j < MIN (i+16, n); ++j)
        if (c_isprint ((*(char **)buf_rtn)[j]))
          printf ("%c", (*(char **)buf_rtn)[j]);
        else
          printf (".");
      for (; j < i+16; ++j)
        printf (" ");
      printf ("|\n");
    }
  }
#endif

  return 0;
}