diff mbox series

[for-3.2,03/41] slirp: simplify fork_exec()

Message ID 20181114123643.24091-4-marcandre.lureau@redhat.com
State New
Headers show
Series RFC: slirp: make it again a standalone project | expand

Commit Message

Marc-André Lureau Nov. 14, 2018, 12:36 p.m. UTC
Use g_spawn_async_with_fds() to setup the child.

GSpawn handles reaping the child, and closing parent file descriptors.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 slirp/misc.c | 75 +++++++++++++++++++++++++---------------------------
 1 file changed, 36 insertions(+), 39 deletions(-)

Comments

Daniel P. Berrangé Nov. 14, 2018, 2:22 p.m. UTC | #1
On Wed, Nov 14, 2018 at 04:36:05PM +0400, Marc-André Lureau wrote:
> Use g_spawn_async_with_fds() to setup the child.
> 
> GSpawn handles reaping the child, and closing parent file descriptors.

The g_spawn* family of APIs is portable to Win32, which the current
fork/exec code in slirp is not.

So I'm curious if this conversion is sufficient to make this part
of slirp work on Win32, or if further portability problems remain.
If it does work on Win32, then you can also delete the stub
fork_exec() impl the code currently has.

> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  slirp/misc.c | 75 +++++++++++++++++++++++++---------------------------
>  1 file changed, 36 insertions(+), 39 deletions(-)
> 
> diff --git a/slirp/misc.c b/slirp/misc.c
> index 7362e14339..7972b9b05b 100644
> --- a/slirp/misc.c
> +++ b/slirp/misc.c
> @@ -129,56 +129,53 @@ err:
>      return -1;
>  }
>  
> +static void
> +fork_exec_child_setup(gpointer data)
> +{
> +    setsid();
> +}
> +
>  int
>  fork_exec(struct socket *so, const char *ex)
>  {
> -	char **argv;
> -	int opt, c, sp[2];
> -	pid_t pid;
> +    GError *err = NULL;
> +    char **argv;
> +    int opt, sp[2];
>  
> -	DEBUG_CALL("fork_exec");
> -	DEBUG_ARG("so = %p", so);
> -	DEBUG_ARG("ex = %p", ex);
> +    DEBUG_CALL("fork_exec");
> +    DEBUG_ARG("so = %p", so);
> +    DEBUG_ARG("ex = %p", ex);
>  
>      if (slirp_socketpair_with_oob(sp) < 0) {
>          return 0;
>      }
>  
> -	pid = fork();
> -	switch(pid) {
> -	 case -1:
> -		error_report("Error: fork failed: %s", strerror(errno));
> -		closesocket(sp[0]);
> -		closesocket(sp[1]);
> -		return 0;
> -
> -	 case 0:
> -		setsid();
> -		dup2(sp[1], 0);
> -		dup2(sp[1], 1);
> -		dup2(sp[1], 2);
> -		for (c = getdtablesize() - 1; c >= 3; c--)
> -		   close(c);
> +    argv = g_strsplit(ex, " ", -1);
> +    g_spawn_async_with_fds(NULL /* cwd */,
> +                           argv,
> +                           NULL /* env */,
> +                           G_SPAWN_SEARCH_PATH,
> +                           fork_exec_child_setup, NULL /* data */,
> +                           NULL /* child_pid */,
> +                           sp[1], sp[1], sp[1],
> +                           &err);
> +    g_strfreev(argv);
>  
> -                argv = g_strsplit(ex, " ", -1);
> -		execvp(argv[0], (char **)argv);
> -
> -		/* 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);
> +    if (err) {
> +        error_report("%s", err->message);
> +        g_error_free(err);
> +        closesocket(sp[0]);
> +        closesocket(sp[1]);
> +        return 0;
> +    }
>  
> -	 default:
> -		so->s = sp[0];
> -		closesocket(sp[1]);
> -		qemu_add_child_watch(pid);
> -		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;
> -	}
> +    so->s = sp[0];
> +    closesocket(sp[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
>  
> -- 
> 2.19.1.708.g4ede3d42df
> 
> 

Regards,
Daniel
Samuel Thibault Nov. 19, 2018, 10:56 p.m. UTC | #2
Marc-André Lureau, le mer. 14 nov. 2018 16:36:05 +0400, a ecrit:
> Use g_spawn_async_with_fds() to setup the child.
> 
> GSpawn handles reaping the child, and closing parent file descriptors.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Applied to my slirp-2 tree, thanks!

Samuel
Samuel Thibault Nov. 19, 2018, 10:59 p.m. UTC | #3
Hello,

Daniel P. Berrangé, le mer. 14 nov. 2018 14:22:34 +0000, a ecrit:
> On Wed, Nov 14, 2018 at 04:36:05PM +0400, Marc-André Lureau wrote:
> > Use g_spawn_async_with_fds() to setup the child.
> > 
> > GSpawn handles reaping the child, and closing parent file descriptors.
> 
> The g_spawn* family of APIs is portable to Win32, which the current
> fork/exec code in slirp is not.
> 
> So I'm curious if this conversion is sufficient to make this part
> of slirp work on Win32, or if further portability problems remain.
> If it does work on Win32, then you can also delete the stub
> fork_exec() impl the code currently has.

Mmm, I don't think any portability issue remains. SO_OOBINLINE is used
in other places, the rest is portable. There is the setsid() call which
may just not make sense on Windows, but we could just disable it there.

I have pushed to 

https://people.debian.org/~sthibault/qemu.git slirp-2-win

what it could look like. I don't have a windows box off hand, could
somebody try it to confirm that it builds?

Samuel
Eric Blake Nov. 19, 2018, 11:20 p.m. UTC | #4
On 11/19/18 4:59 PM, Samuel Thibault wrote:
> Mmm, I don't think any portability issue remains. SO_OOBINLINE is used
> in other places, the rest is portable. There is the setsid() call which
> may just not make sense on Windows, but we could just disable it there.
> 
> I have pushed to
> 
> https://people.debian.org/~sthibault/qemu.git slirp-2-win
> 
> what it could look like. I don't have a windows box off hand, could
> somebody try it to confirm that it builds?

You could try 'make docker-test-mingw@fedora' to at least try building 
for a Windows environment (but that doesn't say much about testing the 
resulting binary).
diff mbox series

Patch

diff --git a/slirp/misc.c b/slirp/misc.c
index 7362e14339..7972b9b05b 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -129,56 +129,53 @@  err:
     return -1;
 }
 
+static void
+fork_exec_child_setup(gpointer data)
+{
+    setsid();
+}
+
 int
 fork_exec(struct socket *so, const char *ex)
 {
-	char **argv;
-	int opt, c, sp[2];
-	pid_t pid;
+    GError *err = NULL;
+    char **argv;
+    int opt, sp[2];
 
-	DEBUG_CALL("fork_exec");
-	DEBUG_ARG("so = %p", so);
-	DEBUG_ARG("ex = %p", ex);
+    DEBUG_CALL("fork_exec");
+    DEBUG_ARG("so = %p", so);
+    DEBUG_ARG("ex = %p", ex);
 
     if (slirp_socketpair_with_oob(sp) < 0) {
         return 0;
     }
 
-	pid = fork();
-	switch(pid) {
-	 case -1:
-		error_report("Error: fork failed: %s", strerror(errno));
-		closesocket(sp[0]);
-		closesocket(sp[1]);
-		return 0;
-
-	 case 0:
-		setsid();
-		dup2(sp[1], 0);
-		dup2(sp[1], 1);
-		dup2(sp[1], 2);
-		for (c = getdtablesize() - 1; c >= 3; c--)
-		   close(c);
+    argv = g_strsplit(ex, " ", -1);
+    g_spawn_async_with_fds(NULL /* cwd */,
+                           argv,
+                           NULL /* env */,
+                           G_SPAWN_SEARCH_PATH,
+                           fork_exec_child_setup, NULL /* data */,
+                           NULL /* child_pid */,
+                           sp[1], sp[1], sp[1],
+                           &err);
+    g_strfreev(argv);
 
-                argv = g_strsplit(ex, " ", -1);
-		execvp(argv[0], (char **)argv);
-
-		/* 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);
+    if (err) {
+        error_report("%s", err->message);
+        g_error_free(err);
+        closesocket(sp[0]);
+        closesocket(sp[1]);
+        return 0;
+    }
 
-	 default:
-		so->s = sp[0];
-		closesocket(sp[1]);
-		qemu_add_child_watch(pid);
-		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;
-	}
+    so->s = sp[0];
+    closesocket(sp[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