Does control return after "execvp()"? - c

if(pid == 0)
{
execvp(cmd, args);
// printf("hello"); // apparently, putting this or not does not work.
_exit(-1);
}
else
{
// parent process work
}
"execvp()" replaces the current program with the to-be-execed program (of course in the same process context). So, putting, say, any printf() calls after execvp() won't work. That is what the docs say, and I have verified it as well.
But then, why is _exit() needed..? Does it so happen that the control DOES return to statements post execvp() ?
I will be grateful for any pointers.
Thanks

The function will return if it has failed.
If one of the exec functions returns to the calling process image, an error has occurred; the return value shall be -1, and errno shall be set to indicate the error.
The _exit() allows terminating the process properly and return an exit code, even if exec fails.

The execve() syscall can fail. The classic reason for doing this would be if the file isn't there or isn't executable. execvp() wraps around execve() to add path searching and default environment handling (virtually always what you want!) and so it adds in another few failure modes, notably trying to run something with a simple name that's not on the user's path. In any case, failure is failure and there's not a lot you can do when it happens except report that it has gone wrong and Get the (now useless) child process Out Of Dodge. (The simplest error reporting method is to print an error message, perhaps with perror(), but there are others.)
The reason why you need _exit() as opposed to the more normal exit() is because you want to quit the child process but you do not want to run any registered cleanup code associated with the parent process. OK, a lot of it might be harmless, but doing things like writing goodbye messages to a socket or something would be bad, and it's often not at all obvious what has been registered with atexit(). Let the parent process worry about its resources; the child basically owns nothing other than its stack frame!

If execvp fails, _exit will be called.
execvp's man page says:
Return Value
If any of the exec() functions returns, an error will have occurred. The return value is -1, and the global variable errno will be set to indicate the error.

One thing to note, you generally don't want a process' exit status to be signed (if portability matters). While exec() is free to return -1 on failure, its returning that so you can handle that failure within the child code.
The actual _exit() status of the child should be 0 - 255, depending on what errno was raised.

Related

Why d we need child exit after execvp?

I have been recently wondering why do we need to use exit after the execution of a child after performing execvp. An in depth explannation is welcome.
You do not need for the child to call exit() after execvp(), but it is often wise for you to ensure that it does so. So much so as to support giving that to novices as a rule.
When a call to execvp() or one of the other exec functions succeeds, it has the effect of replacing the currently-running process image with a new one. As a result, these functions do not return on success, and nothing that follows matters in that case. The issue, then, is entirely about what to do in the event that the exec* call fails.
If you do not exit the child in the event that an exec fails then it will continue running the code of the parent. That is rarely intended or wanted. It may do work that it was not intended to do, delay the parent (that is often wait()ing for it) by not exiting promptly, and eventually mislead the parent with an exit status that is not reflective of what actually happened.
All of that, and perhaps more, is addressed by ensuring that the control flow following an exec* call pretty quickly reaches program termination with a failure status (typically via _Exit() or _exit(); less typically via exit() or abort()). Depending on the circumstances, it may or may not be appropriate to emit a diagnostic message before exiting, or to perform some other kind of cleanup.

Not sure if i'm using exec properly to pass to another program

I have the execlp() call:
execlp("Sequence.c", "Sequence.c", data, NULL);
I'm not sure I'm passing execlp() correctly because the Sequence.c never outputs anything. The current output is only as shown below but I am not too sure what I am doing incorrectly at the moment. From what I know, after I call execlp(), the forked child should run Sequence instead of another instance of Begin, while the parent waits for the forked child to return before running further code.
You should always check for errors. execlp never returns on success, so the "correct" way to call execlp is:
execlp (progname, arg0, arg1, ...., (char *)NULL);
/* If we reach this point, something failed */
perror("execlp failed");
_exit(EXIT_FAILURE);
It is important to call _exit after execlp returns, otherwise we have two processes running the same code. Typically we don't want that. We call _exit rather than exit, since exit does some cleanup, including flushing of buffers. The child process has copies of those buffers, and we don't want them to be flushed twice.
If you give us the error message from perror we could maybe help you. Without error messages there is not much we can do. Except the fact that you are trying to call an executable named *.c, makes us suspect that you are trying to execute a source-file. You know that unless you have a c-code interpreter, c-programs must be compiled, don't you?
You can try this, when you use execlp you are calling Sequence.c, but I'm not sure because I've always use this form ./Sequence, I'm not calling this with c file, but with object file.

Does it make sense to exit(0) after a call to execl()?

Consider the following code:
close(channel_data->pty_master);
if (login_tty(channel_data->pty_slave) != 0) // new terminal session
{
exit(1); // fail
}
execl("/bin/sh", "sh", mode, command, NULL); // replace process image
exit(0);
According to the documentation of execl(), the current process image is being replaced and the call returns only on errors.
But why call exit() after a call to execl() if the process image is replaced?
Exec calls may fail. A common epilogue would be:
perror("Some eror message");
_exit(127); /*or _exit(1); (127 is what shells return) */
You would usually run _exit rather than exit here, in order to skip atexit hooks and stdio buffer flushes.
It does make sense to call exit after some exec(3) function because they can fail (e.g. when execve(2) is failing). The execve(2) page lists a number of failure reasons.
It should better be exit(EXIT_FAILURE) or some other (non 0) exit code (conventionally a high exit code like 127 or 126 would be used for that usage, to separate failure of exec vs errors in the program it would run), and I recommend calling perror just before that exit. As explained by PSKocick there are good reasons to call _exit (but his arguments could be reversed, one would want to run atexit and standard fflushs by using exit instead).
In your case, failure is unlikely, but imagine however if some other process has removed /bin/sh (e.g. the sysadmin making the stupid mistake of running /bin/rm -rf . in the root directory, or in /bin/, perhaps in some other terminal window).
Still that execve could also fail when system resources are (temporarily) exhausted, e.g for
ENOMEM Insufficient kernel memory was available.
And (in rare cases) this could even happen for /bin/sh;
BTW your exec usage would probably fail (with E2BIG) if (by mistake) command was a string of a million of non-null bytes.
As a general coding rule, all important system calls should be checked against failure.
You'll want to call exit because you failed to exec the program in question and you typically don't want that process to hang around since it's not running what you wanted it to run. Since execl only returns on failure, there's no need to check the return status.
In many cases, it also makes sense to print an error message to see why it failed. You should also use an exit code other than 0. A non-zero exit code is used to indicate an abnormal exit, and the parent process can capture that when it calls wait.
execl("/bin/sh", "sh", mode, command, NULL);
perror("command failed");
exit(1);
So yes, it makes sense to cal exit, but not necessarily exit(0).
But why call exit() after a call to execl() if the process image is replaced?
As you said, execl() returns only on errors:
execl("/bin/sh", "sh", mode, command, NULL); // replace process image
exit(0);
In the code above, exit() is called only if the execl() call failed.
As Jonathan Leffler suggested in his comment it may be a very good idea to return a value other than zero, since zero indicates success and the code did indeed fail if the program's control flow ever reached the exit() call in the code above.

Terminating the program gracefully in C

I have sort of a homework and it asks me to end the program gracefully without explicit termination such as calling exit() or killing the threads.
However I cannot think of any other methods than return 0, so what are the methods to end a program gracefully?
Killing the threads is absolutely not a graceful way to terminate a program. I think what your instructor means is that all your parent threads should wait on their child threads before terminating themselves.
Ideally, an explicit call pthread_exit from the main thread would ensure that all it's children continue running even after it exits. Refer to this link. But, the safest way to wait on your child threads before exiting is to use pthread_join.
Nevertheless, exit(0) is the graceful return for a process as such.
I think you are missing to tell us that you have a multi-threaded program. I suppose that the the idea of gracefully terminating the program is meant to terminate all your threads by setting a flag or something like that. And then only to terminate your main after all your threads have provably ended. The way you actually then terminate your main is of lesser importance.
exit(0) generally indicates that process (your program) terminated gracefully. In case of error it would exit(-1) or some other error code.
See my comment.
main will by default return 0 in the lack of a return 0; statement.
See §5.1.2.2.3¶1 of the C99 standard.
If the return type of the main function is a type compatible with int, a return from the
initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the
main function returns a value of 0. If the return type is not compatible with int, the
termination status returned to the host environment is unspecified.
So, the following terminates gracefully although implicitly, distinguished from an explicit exit or return in main.
main() { }
They may be referring to how you handle errors in lower-level routines. Rather than doing something like
printf("ERROR: couldn't initialize the claveman\n");
exit(1);
You would return from that routine (possibly printing the error message at that level or waiting to do it at a higher level like main()).
return CLAVEMAN_INITIALIZE_ERROR;
All your routines would return zero for success or non-zero error codes, up until the code in main was able to return either EXIT_SUCCESS or an error code indicating the failure.
No idea what they could mean with gracefully but my first idea was just a return 0.
Or exit(0)

Unused Return Status Codes in C

I want to return a unique status code to a waiting parent process from a child process through exit(), based on the execution of child's code. If execvp fails, then the exit() is used. I assume that if execvp is successful, the command executed will send its status code.
pid=fork();
if(pid==0)
{
if(execvp(cmdName,cmdArgs)==-1)
{
printf("Exec failed!\n");
exit(K); //K?
}
}
waitpid(pid,&status,0);
Suppose the command passed to execvp() is "ls", the man page says that it may return 0(success), 1 or 2(failure).
What safe unique value K can I use to indicate the return status of a child process, which won't clash with any value returned by the command executed by execvp()?
For obvious reasons, there cannot be such a value of K that will never clash with the return status of any other program.
Proof: Suppose there was such a K, and you make your program call itself...
There is no safe unique value as every program chooses its return values of which there are only a limited number.
You have to document your program and say what it returns and also provide some form of log to give more details.
I believe anything above 127 (or negative, if you use signed byte) is reserved for OS (on Unix) for reporting segfaults, parity errors and such (any exit due to signal handler and some other things besides). All other exit codes you can use.
Update: found a link for Linux: http://www.tldp.org/LDP/abs/html/exitcodes.html

Resources