Also, just imagine something like this:
file.write(blah);
if (has_forked) thread_exit();
file.write(blah2);
if (has_forked) thread_exit();
file.write(blah3)
if (has_forked) thread_exit();
Note the race conditions in the above code... forkall() is a disaster. Presumably you'd combine it with pthread_atfork(), but it's still a total mess.fork() is one of those things that's conceptually quite elegant but in practice has too many problematic edge cases. (Signals seem to fall into the same group.)
I do like that fork, then setup functions, then exec keeps the code simpler. If everything is done as a single call like CreateProcess then it needs to have a way of passing what the setup functions need as data - rather a lot of it.
Meanwhile the Linux/Unix decision was to have about a dozen different APIs to do variants of the same thing (fork, vfork, and clone plus execl, execlp, execle, execv, execvp, execvpe, fexecve, posix_spawn, posix_spawnp, and probably more). This isn't really any less complex.
The argument complexity of CreateProcess could not possibly derive from merging fork() and exec() because fork() has no arguments.
fork(); open(); close(); dup2(); fdcntl(); sigprocmask(); sigaction(); setrlimit(); prctl(); chdir(); chroot(); capset(); execve();
(and perhaps more besides, with new ones potentially added with new features, for example seccomp();)
The question is whether it's better (more elegant) to load that complexity onto one complex function call, or farm it out to multiple simple function calls. It is apparent that this is a question in which personal taste is involved.
The brilliance of fork/exec is in the realization that the tasks you do during process creation are the same as the tasks you do during normal execution, and therefore you can just re-use those functions. For example, CreateProcess has a parameter for the current directory; fork/exec doesn't need one because you just use chdir on the child side of fork.
The proliferation of exec* is indeed baffling, but these are just dumb variants trying to make the exec call itself "easier." They don't reflect any essential complexity.