summaryrefslogtreecommitdiffstats
path: root/src/guestfs.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-07-03 13:22:45 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-07-07 11:32:46 +0100
commitdff126b7c5c322c942ec920fe9fb752137c2e25b (patch)
treeb0f3c70599ba1fbf8e581d3c0b623eb1ecc9f6f6 /src/guestfs.c
parentb6ef5f47cf6355c860f659252a391293ae026a32 (diff)
downloadlibguestfs-dff126b7c5c322c942ec920fe9fb752137c2e25b.tar.gz
libguestfs-dff126b7c5c322c942ec920fe9fb752137c2e25b.tar.xz
libguestfs-dff126b7c5c322c942ec920fe9fb752137c2e25b.zip
New API: guestfs_shutdown: Cleanly shutdown the backend.
The new API splits orderly close into a two-step process: if (guestfs_shutdown (g) == -1) { /* handle the error, eg. qemu error */ } guestfs_close (g); Note that the explicit shutdown step is only necessary in the case where you have made changes to the disk image and want to handle write errors. Read the documentation for further information. This change also: - deprecates guestfs_kill_subprocess - turns guestfs_kill_subprocess into the same as guestfs_shutdown - changes guestfish and other tools to call shutdown + close where necessary (not for read-only tools) - updates documentation - updates examples (cherry picked from commit ffbf1475f7ae7c462db289ad4834391469e72edd)
Diffstat (limited to 'src/guestfs.c')
-rw-r--r--src/guestfs.c103
1 files changed, 64 insertions, 39 deletions
diff --git a/src/guestfs.c b/src/guestfs.c
index d2c5b4eb..ef0ca167 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -172,8 +172,6 @@ guestfs_create (void)
void
guestfs_close (guestfs_h *g)
{
- int status, sig;
-
if (g->state == NO_HANDLE) {
/* Not safe to call ANY callbacks here, so ... */
fprintf (stderr, _("guestfs_close: called twice on the same handle\n"));
@@ -202,10 +200,6 @@ guestfs_close (guestfs_h *g)
debug (g, "closing guestfs handle %p (state %d)", g, g->state);
- /* Try to sync if autosync flag is set. */
- if (g->autosync && g->state == READY)
- ignore_value (guestfs_internal_autosync (g));
-
/* If we are valgrinding the daemon, then we *don't* want to kill
* the subprocess because we want the final valgrind messages sent
* when we close sockets below. However for normal production use,
@@ -213,42 +207,10 @@ guestfs_close (guestfs_h *g)
* daemon or qemu is not responding).
*/
#ifndef VALGRIND_DAEMON
- /* Kill the qemu subprocess. */
if (g->state != CONFIG)
- ignore_value (guestfs_kill_subprocess (g));
+ ignore_value (guestfs_shutdown (g));
#endif
- /* Close sockets. */
- if (g->fd[0] >= 0)
- close (g->fd[0]);
- if (g->fd[1] >= 0)
- close (g->fd[1]);
- if (g->sock >= 0)
- close (g->sock);
- g->fd[0] = -1;
- g->fd[1] = -1;
- g->sock = -1;
-
- /* Wait for subprocess(es) to exit. */
- if (g->pid > 0) {
- if (waitpid (g->pid, &status, 0) == -1)
- perror ("waitpid (qemu)");
- if (WIFEXITED (status) && WEXITSTATUS (status) != 0)
- fprintf (stderr, "libguestfs: close: qemu failed (status %d)\n",
- WEXITSTATUS (status));
- else if (WIFSIGNALED (status)) {
- sig = WTERMSIG (status);
- fprintf (stderr, "libguestfs: close: qemu terminated by signal %d (%s)\n",
- sig, strsignal (sig));
- }
- else if (WIFSTOPPED (status)) {
- sig = WSTOPSIG (status);
- fprintf (stderr, "libguestfs: close: qemu stopped by signal %d (%s)\n",
- sig, strsignal (sig));
- }
- }
- if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0);
-
/* Run user close callbacks. */
guestfs___call_callbacks_void (g, GUESTFS_EVENT_CLOSE);
@@ -285,6 +247,69 @@ guestfs_close (guestfs_h *g)
free (g);
}
+/* Shutdown the backend. */
+int
+guestfs__shutdown (guestfs_h *g)
+{
+ int ret = 0;
+ int status, sig;
+
+ if (g->state == CONFIG)
+ return 0;
+
+ /* Try to sync if autosync flag is set. */
+ if (g->autosync && g->state == READY) {
+ if (guestfs_internal_autosync (g) == -1)
+ ret = -1;
+ }
+
+ /* Signal qemu to shutdown cleanly, and kill the recovery process. */
+ if (g->pid > 0) {
+ debug (g, "sending SIGTERM to process %d", g->pid);
+ kill (g->pid, SIGTERM);
+ }
+ if (g->recoverypid > 0) kill (g->recoverypid, 9);
+
+ /* Close sockets. */
+ if (g->fd[0] >= 0)
+ close (g->fd[0]);
+ if (g->fd[1] >= 0)
+ close (g->fd[1]);
+ if (g->sock >= 0)
+ close (g->sock);
+ g->fd[0] = -1;
+ g->fd[1] = -1;
+ g->sock = -1;
+
+ /* Wait for subprocess(es) to exit. */
+ if (g->pid > 0) {
+ if (waitpid (g->pid, &status, 0) == -1) {
+ perrorf (g, "waitpid (qemu)");
+ ret = -1;
+ }
+ else if (WIFEXITED (status) && WEXITSTATUS (status) != 0) {
+ error (g, "qemu failed (status %d)", WEXITSTATUS (status));
+ ret = -1;
+ }
+ else if (WIFSIGNALED (status)) {
+ sig = WTERMSIG (status);
+ error (g, "qemu terminated by signal %d (%s)", sig, strsignal (sig));
+ ret = -1;
+ }
+ else if (WIFSTOPPED (status)) {
+ sig = WSTOPSIG (status);
+ error (g, "qemu stopped by signal %d (%s)", sig, strsignal (sig));
+ ret = -1;
+ }
+ }
+ if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0);
+
+ g->pid = g->recoverypid = 0;
+ g->state = CONFIG;
+
+ return ret;
+}
+
/* Close all open handles (called from atexit(3)). */
static void
close_handles (void)