Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I execute a shell or system call without a fork?

I have a TCP server application which occasionally needs to reconfigure the bound ports by closing them and then opening them at a later time.

The application also needs to execute an external binary with communication to it. This is currently done using a popen() call. The external binary run time can span the period when the network ports need to be reconfigured.

The problem is, when the main application closes a port it is taken on by the 'forked' process which popen has created to run the binary.

That makes sense (it's discussed at What happens when a tcp server binds and forks before doing an accept ? Which process would handle the client requests? ), but is undesirable, as the main application is then unable to reopen the port.

Is this where FD_CLOEXEC O_CLOEXEC as available in popen(3) can be used? The application needs the pipe that popen(3) offers as stdin to the binary which is executed, is that filehandle left open when CLOEXEC closes the others.

Is there a better way to run the binary, which won't result in a forked process which will hold on to a closed port?

There is another, possibly related question at How to fork process without inheriting handles?

like image 927
rolinger Avatar asked Oct 14 '25 18:10

rolinger


1 Answers

No, you cannot start another program and get back from it without fork(2) followed by some execve(2) code (which is what popen, posix_spawn, and system are doing). You'll better avoid popen or system and code the pipe+fork+execve explicitly yourself (since you know which file descriptors should be kept and which to close(2), generally after the fork and before the execve in the child process...), see this.

(every process & program, except /sbin/init and some hotplug things, is started with fork + execve; and your shell is constantly using fork + execve for most commands, except the builtin ones like cd)

the fork(2) call could be implemented by clone(2).

Read some good book like the Advanced Linux Programming book freely available online here. See also syscalls(2). Use (at least for debugging and to understand things) strace(1) and your debugger (gdb). Study the source code of popen and of system in your free software libc (GNU libc or musl-libc), and the source code of your shell.

You could nearly mimic execve(2) by a tricky sequence of mmap(2) (and related munmap) calls, but not quite (in particular w.r.t. close-on-exec etc...). You'll probably need also to call the obsolete setcontext(3) (or write the equivalent assembler code).

You might consider communicating with a specialized shell-like server-like program doing the fork & execve (see my execicar.c for example and inspiration). Maybe you'll find daemon(3) useful.

A better alternative might be to embed some interpreter (like lua or guile) in your application and/or to dlopen(3) some plugin. The disadvantage is that a bug (in the interpreted script or the plugin) affects your entire server.

like image 138
Basile Starynkevitch Avatar answered Oct 17 '25 08:10

Basile Starynkevitch