diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-07-03 13:22:45 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-07-07 11:32:46 +0100 |
commit | dff126b7c5c322c942ec920fe9fb752137c2e25b (patch) | |
tree | b0f3c70599ba1fbf8e581d3c0b623eb1ecc9f6f6 /src/guestfs.c | |
parent | b6ef5f47cf6355c860f659252a391293ae026a32 (diff) | |
download | libguestfs-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.c | 103 |
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) |