8

I'm learning about fork() and exec() commands. It seems like fork() and exec() are usually called together. (fork() creates a new child process, and exec() replaces the current process image with a new one.) However, in what scenarios might you call each function on its own? Are there scenarios like these?

  • 2
    Traditional forkbomb: while(1) fork(); to hog system resources. – Joshua Oct 18 '17 at 21:21
21

Sure! A common pattern in "wrapper" programs is to do various things and then replace itself with some other program with only an exec call (no fork)

#!/bin/sh
export BLAH_API_KEY=blub
...
exec /the/thus/wrapped/program "$@"

A real-life example of this is GIT_SSH (though git(1) does also offer GIT_SSH_COMMAND if you do not want to do the above wrapper program method).

Fork-only is used when spawning a bunch of typically worker processes (e.g. Apache httpd in fork mode (though fork-only better suits processes that need to burn up the CPU and not those that twiddle their thumbs waiting for network I/O to happen)) or for privilege separation used by sshd and other programs on OpenBSD (no exec)

$ doas pkg_add pstree
...
$ pstree | grep sshd
 |-+= 70995 root /usr/sbin/sshd
 | \-+= 28571 root sshd: jhqdoe [priv] (sshd)
 |   \-+- 14625 jhqdoe sshd: jhqdoe@ttyp6 (sshd)

The root sshd has on client connect forked off a copy of itself (28571) and then another copy (14625) for the privilege separation.

13

There are plenty.

Programs that call fork() without exec() are usually following a pattern of spawning child worker processes for performing various tasks in separate processes to the main one. You'll find this in programs as varied as dhclient, php-fpm, and urxvtd.

A program that calls exec() without fork() is chain loading, overlaying its process with a different program image. There is a whole subculture of chain loading utilities that do particular things to process state and then execute another program to run with that revised process state. Such utilities are common in the daemontools family of service and system management toolsets, but are not limited to those. A few examples:

The daemontools family toolsets have a lot of such tools, from machineenv through find-matching-jvm to runtool.

2

In addition to other answers, debuggers, using ptrace, typically make use of the gap between fork and exec. A debuggee should mark itself with PTRACE_TRACEME to indicate that it is being traced by its parent process - the debugger. This is to give required permissions to the debugger.

So a debugger would first fork itself. The child would call ptrace with PTRACE_TRACEME and then call exec. Whichever program the child exec's will now be traceable by the parent.

  • There are many examples of doing things between fork and exec, the most common being redirecting I/O (e.g. setting up pipes). But the question is about doing fork without any exec at all. – Barmar Oct 25 '17 at 18:54
0

exec without fork

There are at least two reasons why you would want to do such a thing:

  1. Chain loading. The current process image is replaced with something different.
  2. Restarting the currently running program (might for example happen when you SIGHUP or such a server process, reloading everything and doing a completely fresh start). In some way, one could argue this is chain loading, only coincidentially with the same program.

fork without exec

That's what every daemon does every time it's started (twice, indeed). This does several things, among them the shell doesn't hang (since the original process that the shell waits on terminates) and the daemon is no longer controlled by the terminal, so closing the shell window doesn't kill the daemon.

Another common use is forking worker children, which was made famous by the apache web server some 25 years ago (nowadays this isn't considered state of the art any more due to being very prone to the thundering herd problem, but it sure provides the darn simplest, most robust server possible).

Yet another common use is to create a consistent snapshot. fork not only creates a process, it also copies (in theory, in reality it only marks pages copy-on-write) the address space. This (atomically) creates a snapshot of the complete program data which the parent can no longer modify.
Some programs take advantage of that. For example redis saves data to disk (in a consistent state) while at the same time modifying the data set concurrently. This only works because fork created a consistent snapshot that doesn't see the modifications made by the parent process.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.