X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fguestfs.c;h=e0f60f4d42f5732541711c95b7676564e312343e;hb=26991ebb8181b57f4c8454f2862c938d7c5d012d;hp=850264e1c03924f0c7cc54ff22fcb093c1031396;hpb=d4a202aa7bf45382e84f558239dadc24c73d195d;p=libguestfs.git diff --git a/src/guestfs.c b/src/guestfs.c index 850264e..e0f60f4 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -86,6 +86,12 @@ #define safe_strdup guestfs_safe_strdup //#define safe_memdup guestfs_safe_memdup +#ifdef __linux__ +#define CAN_CHECK_PEER_EUID 1 +#else +#define CAN_CHECK_PEER_EUID 0 +#endif + static void default_error_cb (guestfs_h *g, void *data, const char *msg); static int send_to_daemon (guestfs_h *g, const void *v_buf, size_t n); static int recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn); @@ -104,8 +110,27 @@ static int qemu_supports (guestfs_h *g, const char *option); #define xdr_uint32_t xdr_u_int32_t #endif -/* Also in guestfsd.c */ -#define GUESTFWD_ADDR "10.0.2.4" +/* Network configuration of the appliance. Note these addresses are + * only meaningful within the context of the running appliance. QEMU + * translates network connections to these magic addresses into + * userspace calls on the host (eg. connect(2)). qemu-doc has a nice + * diagram which is also useful to refer to. + * + * NETWORK: The network. + * + * ROUTER: The address of the "host", ie. this library. + * + * [Note: If you change NETWORK and ROUTER then you also have to + * change the network configuration in appliance/init]. + * + * GUESTFWD_ADDR, GUESTFWD_PORT: The guestfwd feature of qemu + * magically connects this pseudo-address to the guestfwd channel. In + * typical Linux configurations of libguestfs, guestfwd is not + * actually used any more. + */ +#define NETWORK "169.254.0.0/16" +#define ROUTER "169.254.2.2" +#define GUESTFWD_ADDR "169.254.2.4" #define GUESTFWD_PORT "6666" /* GuestFS handle and connection. */ @@ -1053,7 +1078,7 @@ guestfs__launch (guestfs_h *g) goto cleanup0; /* Choose which vmchannel implementation to use. */ - if (qemu_supports (g, "-net user")) { + if (CAN_CHECK_PEER_EUID && qemu_supports (g, "-net user")) { /* The "null vmchannel" implementation. Requires SLIRP (user mode * networking in qemu) but no other vmchannel support. The daemon * will connect back to a random port number on localhost. @@ -1183,10 +1208,11 @@ guestfs__launch (guestfs_h *g) */ if (null_vmchannel_sock) { add_cmdline (g, "-net"); - add_cmdline (g, "user,vlan=0,net=10.0.2.0/8"); + add_cmdline (g, "user,vlan=0,net=" NETWORK); snprintf (buf, sizeof buf, - "guestfs_vmchannel=tcp:10.0.2.2:%d", null_vmchannel_sock); + "guestfs_vmchannel=tcp:" ROUTER ":%d", + null_vmchannel_sock); vmchannel = strdup (buf); } @@ -1209,7 +1235,7 @@ guestfs__launch (guestfs_h *g) add_cmdline (g, buf); snprintf (buf, sizeof buf, - "user,vlan=0,net=10.0.2.0/8," + "user,vlan=0,net=" NETWORK "," "guestfwd=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT "-chardev:guestfsvmc"); @@ -1229,7 +1255,7 @@ guestfs__launch (guestfs_h *g) add_cmdline (g, "-net"); add_cmdline (g, buf); add_cmdline (g, "-net"); - add_cmdline (g, "user,vlan=0,net=10.0.2.0/8"); + add_cmdline (g, "user,vlan=0,net=" NETWORK); vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT; } @@ -1251,10 +1277,12 @@ guestfs__launch (guestfs_h *g) "%s " /* (selinux) */ "%s " /* (vmchannel) */ "%s " /* (verbose) */ + "TERM=%s " /* (TERM environment variable) */ "%s", /* (append) */ g->selinux ? "selinux=1 enforcing=0" : "selinux=0", vmchannel ? vmchannel : "", g->verbose ? "guestfs_verbose=1" : "", + getenv ("TERM") ? : "linux", g->append ? g->append : ""); add_cmdline (g, "-kernel"); @@ -1281,7 +1309,7 @@ guestfs__launch (guestfs_h *g) if (dup (wfd[0]) == -1) { dup_failed: perror ("dup failed"); - _exit (1); + _exit (EXIT_FAILURE); } if (dup (rfd[1]) == -1) goto dup_failed; @@ -1301,7 +1329,7 @@ guestfs__launch (guestfs_h *g) execv (g->qemu, g->cmdline); /* Run qemu. */ perror (g->qemu); - _exit (1); + _exit (EXIT_FAILURE); } /* Parent (library). */ @@ -1333,11 +1361,11 @@ guestfs__launch (guestfs_h *g) */ for (;;) { if (kill (qemu_pid, 0) == -1) /* qemu's gone away, we aren't needed */ - _exit (0); + _exit (EXIT_SUCCESS); if (kill (parent_pid, 0) == -1) { /* Parent's gone away, qemu still around, so kill qemu. */ kill (qemu_pid, 9); - _exit (0); + _exit (EXIT_SUCCESS); } sleep (2); } @@ -1397,6 +1425,7 @@ guestfs__launch (guestfs_h *g) "libguestfs: warning: unexpected connection from UID %d to port %d\n", uid, null_vmchannel_sock); close (sock); + sock = -1; continue; } } @@ -1491,7 +1520,7 @@ guestfs__launch (guestfs_h *g) close (wfd[1]); close (rfd[0]); } - kill (g->pid, 9); + if (g->pid > 0) kill (g->pid, 9); if (g->recoverypid > 0) kill (g->recoverypid, 9); waitpid (g->pid, NULL, 0); if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); @@ -1737,6 +1766,7 @@ is_openable (guestfs_h *g, const char *path, int flags) static int check_peer_euid (guestfs_h *g, int sock, uid_t *rtn) { +#if CAN_CHECK_PEER_EUID struct sockaddr_in peer; socklen_t addrlen = sizeof peer; @@ -1805,6 +1835,12 @@ check_peer_euid (guestfs_h *g, int sock, uid_t *rtn) error (g, "check_peer_euid: no matching TCP connection found in /proc/net/tcp"); fclose (fp); return -1; +#else /* !CAN_CHECK_PEER_EUID */ + /* This function exists but should never be called in this + * configuration. + */ + abort (); +#endif /* !CAN_CHECK_PEER_EUID */ } /* You had to call this function after launch in versions <= 1.0.70, @@ -1832,7 +1868,7 @@ guestfs__kill_subprocess (guestfs_h *g) if (g->verbose) fprintf (stderr, "sending SIGTERM to process %d\n", g->pid); - kill (g->pid, SIGTERM); + if (g->pid > 0) kill (g->pid, SIGTERM); if (g->recoverypid > 0) kill (g->recoverypid, 9); return 0; @@ -1983,7 +2019,7 @@ child_cleanup (guestfs_h *g) if (g->verbose) fprintf (stderr, "child_cleanup: %p: child process died\n", g); - /*kill (g->pid, SIGTERM);*/ + /*if (g->pid > 0) kill (g->pid, SIGTERM);*/ if (g->recoverypid > 0) kill (g->recoverypid, 9); waitpid (g->pid, NULL, 0); if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); @@ -2350,8 +2386,16 @@ accept_from_daemon (guestfs_h *g) int sock = -1; while (sock == -1) { + /* If the qemu process has died, clean up the zombie (RHBZ#579155). + * By partially polling in the select below we ensure that this + * function will be called eventually. + */ + waitpid (g->pid, NULL, WNOHANG); + rset2 = rset; - int r = select (max_fd+1, &rset2, NULL, NULL, NULL); + + struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; + int r = select (max_fd+1, &rset2, NULL, NULL, &tv); if (r == -1) { if (errno == EINTR || errno == EAGAIN) continue;