/** * 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); }
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); }
/** * 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; }