X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fguestfs.c;h=747aae50453133d279c9e6088f154e2f2ee61d11;hp=309cd15b56799d0891e7c7c40a956f630a807176;hb=c9cc61940b41b1abb763a1932adfc3461372c10b;hpb=40ca9a57829f2e82362e391d7d998bf33c8bd671 diff --git a/src/guestfs.c b/src/guestfs.c index 309cd15..747aae5 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -67,6 +67,8 @@ static void stdout_event (void *data, int watch, int fd, int events); static void sock_read_event (void *data, int watch, int fd, int events); static void sock_write_event (void *data, int watch, int fd, int events); +static void close_handles (void); + static int select_add_handle (guestfs_h *g, int fd, int events, guestfs_handle_event_cb cb, void *data); static int select_remove_handle (guestfs_h *g, int watch); static int select_add_timeout (guestfs_h *g, int interval, guestfs_handle_timeout_cb cb, void *data); @@ -95,6 +97,8 @@ enum state { CONFIG, LAUNCHING, READY, BUSY, NO_HANDLE }; struct guestfs_h { + struct guestfs_h *next; /* Linked list of open handles. */ + /* State: see the state machine diagram in the man page guestfs(3). */ enum state state; @@ -112,6 +116,7 @@ struct guestfs_h int cmdline_size; int verbose; + int autosync; /* Callbacks. */ guestfs_abort_cb abort_cb; @@ -144,6 +149,9 @@ struct guestfs_h int msg_next_serial; }; +static guestfs_h *handles = NULL; +static int atexit_handler_set = 0; + guestfs_h * guestfs_create (void) { @@ -170,6 +178,26 @@ guestfs_create (void) str = getenv ("LIBGUESTFS_DEBUG"); g->verbose = str != NULL && strcmp (str, "1") == 0; + /* Start with large serial numbers so they are easy to spot + * inside the protocol. + */ + g->msg_next_serial = 0x00123400; + + /* Link the handles onto a global list. This is the one area + * where the library needs to be made thread-safe. (XXX) + */ + /* acquire mutex (XXX) */ + g->next = handles; + handles = g; + if (!atexit_handler_set) { + atexit (close_handles); + atexit_handler_set = 1; + } + /* release mutex (XXX) */ + + if (g->verbose) + fprintf (stderr, "new guestfs handle %p\n", g); + return g; } @@ -178,6 +206,7 @@ guestfs_close (guestfs_h *g) { int i; char filename[256]; + guestfs_h *gg; if (g->state == NO_HANDLE) { /* Not safe to call 'error' here, so ... */ @@ -185,6 +214,13 @@ guestfs_close (guestfs_h *g) return; } + if (g->verbose) + fprintf (stderr, "closing guestfs handle %p (state %d)\n", g, g->state); + + /* Try to sync if autosync flag is set. */ + if (g->autosync && g->state == READY) + guestfs_sync (g); + /* Remove any handlers that might be called back before we kill the * subprocess. */ @@ -211,9 +247,26 @@ guestfs_close (guestfs_h *g) /* Mark the handle as dead before freeing it. */ g->state = NO_HANDLE; + /* acquire mutex (XXX) */ + if (handles == g) + handles = g->next; + else { + for (gg = handles; gg->next != g; gg = gg->next) + ; + gg->next = g->next; + } + /* release mutex (XXX) */ + free (g); } +/* Close all open handles (called from atexit(3)). */ +static void +close_handles (void) +{ + while (handles) guestfs_close (handles); +} + static void default_error_cb (guestfs_h *g, void *data, const char *msg) { @@ -330,6 +383,18 @@ guestfs_get_verbose (guestfs_h *g) return g->verbose; } +void +guestfs_set_autosync (guestfs_h *g, int a) +{ + g->autosync = a; +} + +int +guestfs_get_autosync (guestfs_h *g) +{ + return g->autosync; +} + /* Add a string to the current command line. */ static void incr_cmdline_size (guestfs_h *g) @@ -492,7 +557,8 @@ guestfs_launch (guestfs_h *g) "console=ttyS0 guestfs=%s:%d", VMCHANNEL_ADDR, VMCHANNEL_PORT); add_cmdline (g, "-m"); - add_cmdline (g, "384"); /* XXX Choose best size. */ + add_cmdline (g, "384"); /* XXX Choose best size. */ + add_cmdline (g, "-no-kqemu"); /* Avoids a warning. */ add_cmdline (g, "-kernel"); add_cmdline (g, (char *) kernel); add_cmdline (g, "-initrd"); @@ -525,6 +591,8 @@ guestfs_launch (guestfs_h *g) close (rfd[0]); dup (wfd[0]); dup (rfd[1]); + close (wfd[0]); + close (rfd[1]); #if 0 /* Set up a new process group, so we can signal this process @@ -862,13 +930,13 @@ sock_read_event (void *data, int watch, int fd, int events) goto cleanup; } - if (g->msg_in_size < len) return; /* Need more of this message. */ + if (g->msg_in_size-4 < len) return; /* Need more of this message. */ /* This should not happen, and if it does it probably means we've * lost all hope of synchronization. */ - if (g->msg_in_size > len) { - error (g, "len = %d, but msg_in_size = %d", len, g->msg_in_size); + if (g->msg_in_size-4 > len) { + error (g, "len = %d, but msg_in_size-4 = %d", len, g->msg_in_size-4); goto cleanup; } @@ -944,7 +1012,7 @@ sock_write_event (void *data, int watch, int fd, int events) return; if (g->verbose) - fprintf (stderr, "sock_write_event: done writing, switching back to reading events\n", n); + fprintf (stderr, "sock_write_event: done writing, switching back to reading events\n"); free (g->msg_out); g->msg_out_pos = g->msg_out_size = 0; @@ -1047,6 +1115,38 @@ dispatch (guestfs_h *g, int proc_nr, xdrproc_t xdrp, char *args) return -1; } +/* Check the return message from a call for validity. */ +static int +check_reply_header (guestfs_h *g, + const struct guestfs_message_header *hdr, + int proc_nr, int serial) +{ + if (hdr->prog != GUESTFS_PROGRAM) { + error (g, "wrong program (%d/%d)", hdr->prog, GUESTFS_PROGRAM); + return -1; + } + if (hdr->vers != GUESTFS_PROTOCOL_VERSION) { + error (g, "wrong protocol version (%d/%d)", + hdr->vers, GUESTFS_PROTOCOL_VERSION); + return -1; + } + if (hdr->direction != GUESTFS_DIRECTION_REPLY) { + error (g, "unexpected message direction (%d/%d)", + hdr->direction, GUESTFS_DIRECTION_REPLY); + return -1; + } + if (hdr->proc != proc_nr) { + error (g, "unexpected procedure number (%d/%d)", hdr->proc, proc_nr); + return -1; + } + if (hdr->serial != serial) { + error (g, "unexpected serial (%d/%d)", hdr->serial, serial); + return -1; + } + + return 0; +} + /* The high-level actions are autogenerated by generator.ml. Include * them here. */