summaryrefslogtreecommitdiff
path: root/slirp/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'slirp/misc.c')
-rw-r--r--slirp/misc.c174
1 files changed, 53 insertions, 121 deletions
diff --git a/slirp/misc.c b/slirp/misc.c
index 1940a8a75f..c0259ae8d7 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -78,7 +78,7 @@ void slirp_destroy_exec_list(struct ex_list *exec_list)
#ifdef _WIN32
int
-fork_exec(struct socket *so, const char *ex, int do_pty)
+fork_exec(struct socket *so, const char *command)
{
/* not implemented */
return 0;
@@ -87,136 +87,68 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
#else
/*
- * XXX This is ugly
- * We create and bind a socket, then fork off to another
- * process, which connects to this socket, after which we
- * exec the wanted program. If something (strange) happens,
- * the accept() call could block us forever.
+ * Create a socket pair, fork another process and execute the wanted program,
+ * inetd style (stdio is linked to the socket pair).
*
- * do_pty = 0 Fork/exec inetd style
- * do_pty = 1 Fork/exec using slirp.telnetd
- * do_ptr = 2 Fork/exec using pty
+ * Returns 1 on success and 0 on failure.
*/
int
-fork_exec(struct socket *so, const char *ex, int do_pty)
+fork_exec(struct socket *so, const char *command)
{
- int s;
- struct sockaddr_in addr;
- socklen_t addrlen = sizeof(addr);
- int opt;
- const char *argv[256];
- /* don't want to clobber the original */
- char *bptr;
- const char *curarg;
- int c, i, ret;
- pid_t pid;
-
- DEBUG_CALL("fork_exec");
- DEBUG_ARG("so = %p", so);
- DEBUG_ARG("ex = %p", ex);
- DEBUG_ARG("do_pty = %x", do_pty);
-
- if (do_pty == 2) {
- return 0;
- } else {
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
- bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
- listen(s, 1) < 0) {
- error_report("Error: inet socket: %s", strerror(errno));
- if (s >= 0) {
- closesocket(s);
- }
-
- return 0;
- }
- }
-
- pid = fork();
- switch(pid) {
- case -1:
- error_report("Error: fork failed: %s", strerror(errno));
- close(s);
- return 0;
-
- case 0:
- setsid();
-
- /* Set the DISPLAY */
- getsockname(s, (struct sockaddr *)&addr, &addrlen);
- close(s);
- /*
- * Connect to the socket
- * XXX If any of these fail, we're in trouble!
- */
- s = qemu_socket(AF_INET, SOCK_STREAM, 0);
- addr.sin_addr = loopback_addr;
- do {
- ret = connect(s, (struct sockaddr *)&addr, addrlen);
- } while (ret < 0 && errno == EINTR);
+ int r, s, opt;
+ int sockets[2];
+ pid_t pid;
+ gchar **argv;
+
+ if (command[0] == '\0') {
+ error_report("slirp: and empty command was given");
+ return 0;
+ }
- dup2(s, 0);
- dup2(s, 1);
- dup2(s, 2);
- for (s = getdtablesize() - 1; s >= 3; s--)
- close(s);
+ r = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
+ if (r < 0) {
+ error_report("slirp: failed to create socketpair: %s", strerror(errno));
+ return 0;
+ }
- i = 0;
- bptr = g_strdup(ex); /* No need to free() this */
- if (do_pty == 1) {
- /* Setup "slirp.telnetd -x" */
- argv[i++] = "slirp.telnetd";
- argv[i++] = "-x";
- argv[i++] = bptr;
- } else
- do {
- /* Change the string into argv[] */
- curarg = bptr;
- while (*bptr != ' ' && *bptr != (char)0)
- bptr++;
- c = *bptr;
- *bptr++ = (char)0;
- argv[i++] = g_strdup(curarg);
- } while (c);
+ pid = fork();
+ switch (pid) {
+ case -1:
+ error_report("Error: fork failed: %s", strerror(errno));
+ close(sockets[0]);
+ close(sockets[1]);
+ return 0;
+
+ case 0:
+ setsid();
+ s = sockets[0];
+ close(sockets[1]);
+ dup2(s, 0);
+ dup2(s, 1);
+ dup2(s, 2); /* XXX really clobber network with stderr? */
+ for (s = getdtablesize() - 1; s >= 3; s--) {
+ close(s);
+ }
- argv[i] = NULL;
- execvp(argv[0], (char **)argv);
+ argv = g_strsplit(command, " ", -1);
+ execvp(argv[0], (char **)argv);
- /* Ooops, failed, let's tell the user why */
+ /* Ooops, failed, let's tell the user why */
fprintf(stderr, "Error: execvp of %s failed: %s\n",
argv[0], strerror(errno));
- close(0); close(1); close(2); /* XXX */
- exit(1);
-
- default:
- qemu_add_child_watch(pid);
- /*
- * XXX this could block us...
- * XXX Should set a timer here, and if accept() doesn't
- * return after X seconds, declare it a failure
- * The only reason this will block forever is if socket()
- * of connect() fail in the child process
- */
- do {
- so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
- } while (so->s < 0 && errno == EINTR);
- closesocket(s);
- socket_set_fast_reuse(so->s);
- opt = 1;
- qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
- qemu_set_nonblock(so->s);
-
- /* Append the telnet options now */
- if (so->so_m != NULL && do_pty == 1) {
- sbappend(so, so->so_m);
- so->so_m = NULL;
- }
-
- return 1;
- }
+ exit(1);
+
+ default:
+ qemu_add_child_watch(pid);
+ close(sockets[0]);
+ so->s = sockets[1];
+ socket_set_fast_reuse(so->s);
+ opt = 1;
+ qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+ qemu_set_nonblock(so->s);
+
+ return 1;
+ }
}
#endif