What to do if exec() fails? - c

Let's suppose we have a code doing something like this:
int pipes[2];
pipe(pipes);
pid_t p = fork();
if(0 == p)
{
dup2(pipes[1], STDOUT_FILENO);
execv("/path/to/my/program", NULL);
...
}
else
{
//... parent process stuff
}
As you can see, it's creating a pipe, forking and using the pipe to read the child's output (I can't use popen here, because I also need the PID of the child process for other purposes).
Question is, what should happen if in the above code, execv fails? Should I call exit() or abort()? As far as I know, those functions close the open file descriptors. Since fork-ed process inherits the parent's file descriptors, does it mean that the file descriptors used by the parent process will become unusable?
UPD
I want to emphasize that the question is not about the executable loaded by exec() failing, but exec itself, e.g. in case the file referred by the first argument is not found or is not executable.

You should use exit(int) since the (low byte) of the argument can be read by the parent process using waitpid(). This lets you handle the error appropriately in the parent process. Depending on what your program does you may want to use _exit instead of exit. The difference is that _exit will not run functions registered with atexit nor will it flush stdio streams.

There are about a dozen reasons execv() can fail and you might want to handle each differently.
The child failing is not going to affect the parent's file descriptors. They are, in effect, reference counted.

You should call _exit(). It does everything exit() does, but it avoids invoking any registered atexit() functions. Calling _exit() means that the parent will be able to get your failed child's exit status, and take any necessary steps.

Related

What is the best way to close a nonstandard anonymous pipe handle for child process on Windows?

On Linux, the pseudo-code looks roughly like this:
setup_env();
pid = fork();
if (pid == 0) {
// we are the child
closeUnusedPipeEnd();
setup_child();
execve();
}
closeOtherUnusedPipeEnd();
posix_spawn uses file_actions to register what the child process would do in spawnp, which boils down to a clone() instead of fork().
However, I do not find Windows examples for how to close the unused end of the anonymous pipe in the child process.
Is my only option to do this inside the child process, for example via stdin parsing or environment variables?
Or what is considered best practice in Windows for anonymous pipes?
The pipe handles are assumed to be created from kernel32.CreateNamedPipeW and kernel32.CreateFileW and read handle for overlapped IO (FILE_FLAG_OVERLAPPED).
One should use kernel32.SetHandleInformation() with HANDLE_FLAG_INHERIT to only inherit the pipe end used in the child process.

Need clarification regarding vfork use

I want to run the child process earlier than the parent process. I just want to use execv call from the child process, So i am using vfork instead of fork.
But suppose execv fails and returns, i want to return non-zero value from the function in which i am calling vfork.
something like this,
int start_test()
{
int err = 0;
pid_t pid;
pid = vfork();
if(pid == 0) {
execv(APP, ARGS);
err = -1;
_exit(1);
} else if(pid > 0) {
//Do something else
}
return err;
}
Is above code is proper, Or i should use some other mechanism to run child earlier than parent?
On some links, I have read that, We should not modify any parent resource in child process created through vfork(I am modifying err variable).
Is above code is proper?
No. The err variable is already in the child's memory, thus parent will not see its modification.
We should not modify any parent resource in child process created through vfork (I am modifying err variable).
The resource is outdated. Some *nix systems in the past tried to play tricks with the fork()/exec() pair, but generally those optimizations have largely backfired, resulting in unexpected, hard to reproduce problems. Which is why the vfork() was removed from the recent versions of POSIX.
Generally you can make this assumptions about vfork() on modern systems which support it: If the child does something unexpected by the OS, the child would be upgraded from vfork()ed to normal fork()ed one.
For example on Linux the only difference between fork() and vfork() is that in later case, more of the child's data are made into lazy COW data. The effect is that vfork() is slightly faster than fork(), but child is likely to sustain some extra performance penalty if it tries to access the yet-not-copied data, since they are yet to be duplicated from the parent. (Notice the subtle problem: parent can also modify the data. That would also trigger the COW and duplication of the data between parent and child processes.)
I just want to use execv call from the child process, So i am using vfork instead of fork.
The handling should be equivalent regardless of the vfork() vs fork(): child should return with a special exit code, and parent should do the normal waitpid() and check the exit status.
Otherwise, if you want to write a portable application, do not use the vfork(): it is not part of the POSIX standard.
P.S. This article might be also of interest. If you still want to use the vfork(), then read this scary official manpage.
Yes. You should not modify the variable err. Use waitpid in the parent process to check the exit code of the child process. Also check the return value from execv and the errno variable(see man execv), to determine why your execv fails.

Does the C execv() function terminate the child proccess?

Heres a breakdown of my code.
I have a program that forks a child (and registers the child's pid in a file) and then does its own thing. The child becomes any program the programmer has dignified with argv. When the child is finished executing, it sends a signal (using SIGUSR1) back to the parent processes so the parent knows to remove the child from the file. The parent should stop a second, acknowledge the deleted entry by updating its table, and continue where it left off.
pid = fork();
switch(pid){
case -1:{
exit(1);
}
case 0 :{
(*table[numP-1]).pid = getpid(); //Global that stores pids
add(); //saves table into a text file
freeT(table); //Frees table
execv(argv[3], &argv[4]); //Executes new program with argv
printf("finished execution\n");
del(getpid()); //Erases pid from file
refreshReq(); //Sends SIGUSR1 to parent
return 0;
}
default:{
... //Does its own thing
}
}
The problem is that the after execv successfully starts and finishes (A printf statement before the return 0 lets me know), I do not see the rest of the commands in the switch statement being executed. I am wondering if the execv has like a ^C command in it which kills the child when it finishes and thus never finishes the rest of the commands. I looked into the man pages but did not find anything useful on the subject.
Thanks!
execv replaces the currently executing program with a different one. It doesn't restore the old program once that new program is done, hence it's documented "on success, execv does not return".
So, you should see your message "finished execution" if and only if execv fails.
execv replaces the current process with a new one. In order to spawn a new process, you can use e.g. system(), popen(), or a combination of fork() and exec()
Other people have already explained what execv and similar functions do, and why the next line of code is never executed. The logical next question is, so how should the parent detect that the child is done?
In the simple cases where the parent should do absolutely nothing while the child is running, just use system instead of fork and exec.
Or if the parent will do something else before the child exits, these are the key points:
When the child exits, the parent will get SIGCHLD. The default handler for SIGCHLD is ignore. If you want to catch that signal, install a handler before calling fork.
After a child has exited, the parent should call waitpid to clean up the child and find out what its exit status was.
The parent can also call wait or waitpid in a blocking mode to wait until a child exits.
The parent can also call waitpid in a non-blocking mode to find out whether the child has exited yet.
What did you expect to happen? This is what execv does. Please read the documentation which says:
The exec() family of functions replaces the current process image with a new process image.
Perhaps you were after system or something, to ask the environment to spawn a new process in addition to the current one. Or.. isn't that what you already achieved through fork? It's hard to see what you want to accomplish here.

Need help with named pipes and popen

I've got a little C server that needs to accept a connection and fork a child process. I need the stderr of the child process to go to an already existing named pipe, the stdout of the child to go to the stdout of the parent, and the stdin of the child tp come from the same place as the stdin of the parent.
My initial attempts involved popen() but I could never seem to get quite what I wanted.
Finally, this particular solution only needs to work in Solaris. Thanks.
EDIT: Updated the question in hopes of more accurately portraying what I'm trying to accomplish. Thanks for being patient with me.
EDIT2: I also need the parent to get the return value of the child process and then do something with it if that makes any difference.
You might be using the wrong function - popen() is used when you want the invoking program either to write to the forked process's standard input or read from its standard output. It seems you want neither. It also takes two arguments.
Your requirements are also somewhat contradictory:
I want it to (ideally) inherit stdin and stdout from the parent
any input to the parent goes to the child and any output from the child goes back to the parent
but at a minimum, I'd like it to inherit stdin and write stdout to a named pipe
The first option is easy - it requires no special coding. Any data supplied to the stdin of the parent will also be available on the stdin of the child (but only one of the two processes will get to read it). The child's stdout will normally go to the same place as the parent's stdout. If you want the parent to read the child's stdout, then you do need a pipe - and popen() is then appropriate, but the 'at minimum' stuff is confusing.
So, let's define what you really want?
Option 1
The standard error of the child should go to a named pipe.
The standard output of the child should be read by the invoking process.
The standard input of the child should come from the same place as the standard input of the parent.
The named pipe already exists.
Hence:
FILE *fp = popen("/run/my/command -with arguments 2>/my/other/pipe", "r");
Note that the child will be hung until a process opens '/my/other/pipe' for reading; that in turn means that if the parent process reads from fp, it too will be hung until some other process opens '/my/other/pipe' for reading.
Option 2
The standard error of the child should go to a named pipe.
The standard output of the child should go to the standard output of the parent.
The standard input of the child should come from the same place as the standard input of the parent.
The named pipe already exists.
Now popen() is not appropriate, and we get into naked `fork & exec' code. What follows is more pseudo-code than operational C.
if ((pid = fork() < 0)
error
else if (pid > 0)
{
/* Parent - might wait for child to complete */
}
else
{
int fd = open("/my/other/pipe", O_WRONLY|O_NONBLOCK);
if (fd < 0)
error
dup2(fd, 2); /* There is a symbolic name for stderr too */
close(fd); /* Do not want this open any more */
char *cmd[4] = { "/bin/sh", "-c", "/run/my/command -with arguments", 0 };
execv(cmd[0], cmd);
error - if execv returns, it failed!
}
If you're totally confident no-one has pulled any stunts on you like closing stdout, you can avoid using dup2() by closing stderr (fd = 2) before calling open(). However, if you do that, you can't report any errors any more - because you closed stderr. So, I would do it as shown.
If you have a different requirement, state what you want to achieve.
As noted by p2vb, if you want the parent to wait for the child to finish, then simply using system() may be sufficient. If the parent should continue while the child is running, you might try system() where the command string ends with an ampersand (&) to put the child into the background, or you might use the code outlined in Option 2 above.
Using system(), the parent will have little chance to read the /my/other/pipe which gets the standard error from the child. You could easily deadlock if the child produces a lot.
Also, be careful with your FD_CLOEXEC flag - set it on files that you don't want the child modifying. On Linux, you can use the O_CLOEXEC flag on the open() call; with Solaris, you have to set it via fcntl() - carefully.

Alternatives to popen/pclose?

I'm writing a program that has to execute other external processes; right now the program launches the processes' commandlines via popen, grabs any output, and then grabs the exit status via pclose.
What is happening, however, is that for fast-running processes (e.g. the launched process errors out quickly) the pclose call cannot get the exit status (pclose returns -1, errno is ECHILD).
Is there a way for me to mimic the popen/pclose type behavior, except in a manner that guarantees capturing the process end "event" and the resultant return code? How do I avoid the inherent race condition with pclose and the termination of the launched process?
fork/exec/wait
popen is just a wrapper to simplify the fork/exec calls. If you want to acquire the output of the child, you'll need to create a pipe, call fork, dup the child's file descriptors to the pipe, and then exec. The parent can read the output from the pipe and call wait to get the child's exit status.
You can use vfork() and execv().

Resources