I do the regular thing:
- fork()
- execvp(cmd, ) in child
If execvp fails because no cmd is found, how can I notice this error in parent process?
I do the regular thing:
If execvp fails because no cmd is found, how can I notice this error in parent process?
Well, you could use the
wait
/waitpid
functions in the parent process. You can specify astatus
variable that holds info about the status of the process that terminated. The downside is that the parent process is blocked until the child process finishes execution.You terminate the child (by calling _exit()) and then the parent can notice this (through e.g. waitpid()). For instance, your child could exit with an exit status of -1 to indicate failure to exec. One caveat with this is that it is impossible to tell from your parent whether the child in its original state (i.e. before exec) returned -1 or if it was the newly executed process.
As suggested in the comments below, using an "unusual" return code would be appropiate to make it easier to distinguish between your specific error and one from the exec()'ed program. Common ones are 1, 2, 3 etc. while higher numbers 99, 100, etc. are more unusual. You should keep your numbers below 255 (unsigned) or 127 (signed) to increase portability.
Since waitpid blocks your application (or rather, the thread calling it) you will either need to put it on a background thread or use the signalling mechanism in POSIX to get information about child process termination. See the SIGCHLD signal and the sigaction function to hook up a listener.
You could also do some error checking before forking, such as making sure the executable exists.
If you use something like Glib, there are utility functions to do this, and they come with pretty good error reporting. Take a look at the "spawning processes" section of the manual.
1) Use
_exit()
notexit()
- see http://opengroup.org/onlinepubs/007908775/xsh/vfork.html - NB: applies tofork()
as well asvfork()
.2) The problem with doing more complicated IPC than the exit status, is that you have a shared memory map, and it's possible to get some nasty state if you do anything too complicated - e.g. in multithreaded code, one of the killed threads (in the child) could have been holding a lock.
The well-known self-pipe trick can be adapted for this purpose.
Here's a complete program.
How this works:
Create a pipe, and make the write endpoint
CLOEXEC
: it auto-closes when anexec
is successfully performed.In the child, try to
exec
. If it succeeds, we no longer have control, but the pipe is closed. If it fails, write the failure code to the pipe and exit.In the parent, try to read from the other pipe endpoint. If
read
returns zero, then the pipe was closed and the child must haveexec
successfully. Ifread
returns data, it's the failure code that our child wrote.Anytime exec fails in a subprocess, you should use kill(getpid(),SIGKILL) and the parent should always have a signal handler for SIGCLD and tell the user of the program, in the appropriate way, that the process was not successfully started.
Not should you wonder how you can notice it in parent process, but also you should keep in mind that you must notice the error in parent process. That's especially true for multithreaded applications.
After execvp you must place a call to function that terminates the process in any case. You should not call any complex functions that interact with C library (such as stdio), since effects of them may mingle with pthreads of libc functionality of parent process. So you can't print a message with
printf()
in child process and have to inform parent about the error instead.The easiest way, among the other, is passing return code. Supply nonzero argument to
_exit()
function (see note below) you used to terminate the child and then examine the return code in the parent. Here's the example:Instead of
_exit()
, you might think ofexit()
function, but it's incorrect, since this function will do a part of the C-library cleanup that should be done only when parent process terminates. Instead, use_exit()
function, that doesn't do such a cleanup.