I read this code in an implementation of the system function of unix (problem 8.22):
int status;
if (wait(&status) > 0) {
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
} else {
return status;
}
}
I don't understand what the if condition is for here: Isn't the status returned by WEXITSTATUS the same as the one in wait? If not, then what is the difference between the two?
The status value is a sort of composite value which includes the process "exit status" plus other bits. From the Linux man page regarding WEXITSTATUS:
If the value of WIFEXITED(stat_val) is non-zero, this macro evaluates
to the low-order 8 bits of the status argument that the child process
passed to _exit() or exit(), or the value the child process returned
from main().
Related
Let's suppose that I wrote the following in main:
int main() {
int status;
if ((p1 = fork()) != 0) {
if ((p2 = fork()) != 0) {
wait(&status);
wait(&status);
} else {
processB();
}
}
return 3;
}
plus:
int processB() {
return 1;
}
when process p2 ends, what will be the value it saves in &status?
If it ended using exit(100) for example then it will return 100, but I don't know what will happen in this case?
The exit status from the process is encoded in 16 bits. The high-order 8 bits contain the return value from main() or the value passed to exit() (or one of its relatives); the low-order 8 bits contain the signal that killed the process and a flag indicating that a core dump was created. The low order bits are zero if the process exited normally. The return value from wait() is the PID of the dead process.
Use code similar to this to print out the information in a semi-legible format:
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("PID %5d exited with status 0x%.4X\n", corpse, status);
If your program has return 3; at the end of main(), then the value reported via the status pointer to wait() will be 0x0300 (768 = 3 * 256). If your program calls exit(100);, the value returned by wait() will be 0x6400 (100 = 6 * 16 + 4). If your program is killed by an interrupt (SIGINT, 2), the value returned by wait() will be 0x0002. (Technically, the actual values are system-dependent, but this is historically accurate and I know of no system where this is not what happens.)
See also ExitCodes bigger than 255 — Possible?.
POSIX defines the <sys/wait.h>
header with a bunch of relevant macros, such as:
WIFEXITED
WEXITSTATUS
WIFSIGNALED
WTERMSIG
WIFSTOPPED
WSTOPSIG
And implementations often define a macro to detect core dumps — usually WCOREDUMP.
See also the POSIX specification for wait()
(which also specifies waitpid()).
(1) Assume, that main process calls fork(), and it returns -1, so process have no children.
After this call in main process called wait(&status), and according to manuals it will return -1. Will 'status' variable stay unchanged, as before call?
(2) Having this situation from (1), if right after wait(&status) line, there is a line status = WEXITSTATUS(status), will 'status' variable change then?
int status = 0;
if (fork()!=0) {
wait(&status);
status = WEXITSTATUS(status);
}
1: undefined behaviour. There is no guarantee that status is unchanged if waitpid failes
2: yes, status = WEXITSTATUS(status); will replace the value in status. (Specifically, WEXITSTATUS should mask away all upper bits of the value)
In the following code:
int main ( int argc, char *argv[] ) {
int i, pid, status;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
if(pid < 0) {
printf("Error occured");
exit(1);
} else if (pid == 0) {
status = system("./frun test.txt 1");
if (status != 0)
printf("ERROR, exited with %d\n", status);
else
printf("SUCCESS, exited with %d\n", status); // 0
exit(0);
} else {
wait(NULL);
}
}
return 0;
}
I am using system() to run a program called 'frun'
My question is - how would I change the code to use one of the exec() family functions instead?
My main problem is that I need to get the exit code of the program and I can't find a way to do it with exec(), while system() just returns the exit status.
Read the manual pages for wait and exec.
You wait on the process created from forking and execing (recall that exec replaces the current process, so you must fork to get its exit code). This is from the man page for wait:
Regardless of its value, this information may be interpreted using the following
macros, which are defined in <sys/wait.h> and evaluate to integral expressions; the
stat_val argument is the integer value pointed to by stat_loc.
WIFEXITED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that
terminated normally.
WEXITSTATUS(stat_val)
If the value of WIFEXITED(stat_val) is non-zero, this macro evaluates to the
low-order 8 bits of the status argument that the child process passed to _exit()
or exit(), or the value the child process returned from main().
WIFSIGNALED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that
terminated due to the receipt of a signal that was not caught (see <signal.h>).
WTERMSIG(stat_val)
If the value of WIFSIGNALED(stat_val) is non-zero, this macro evaluates to the
number of the signal that caused the termination of the child process.
WIFSTOPPED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that is
currently stopped.
WSTOPSIG(stat_val)
If the value of WIFSTOPPED(stat_val) is non-zero, this macro evaluates to the
number of the signal that caused the child process to stop.
WIFCONTINUED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that
has continued from a job control stop.
In your case you'd probably want to use WEXITSTATUS(stat_val) to get the 8 bit exit code.
You call waitpid(pid, stat_loc, options) where you'd pass the pid returned from fork(), a pointer to a local int (where the status is stored), and your options flags (or 0). You would do this is in the branch where pid != 0, since this is the original process. The original process calling fork() (where pid == 0) would call exec and thus be replaced by the exec'd command.
Here is a pseudo-example that you can adapt to your code:
pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
exec(/*look up the different functions in the exec family and how to use them*/);
}
else if (pid < 0)
{
//uh oh
}
else
{
waitpid(pid, &status, 0);
printf("Exited with %d\n", WEXITSTATUS(status));
}
Though you should check the result of waitpid.
I have this code:
int status;
t = wait(&status);
When the child process works, the value of status is 0, well.
But why does it return 256 when it doesn't work? And why changing the value of the argument given to exit in the child process when there is an error doesn't change anything (exit(2) instead of exit(1) for example)?
Edit : I'm on linux, and I compiled with GCC.
Given code like this...
int main(int argc, char **argv) {
pid_t pid;
int res;
pid = fork();
if (pid == 0) {
printf("child\n");
exit(1);
}
pid = wait(&res);
printf("raw res=%d\n", res);
return 0;
}
...the value of res will be 256. This is because the return value from wait encodes both the exit status of the process as well as the reason the process exited. In general, you should not attempt to interpret non-zero return values from wait directly; you should use of the WIF... macros. For example, to see if a process exited normally:
WIFEXITED(status)
True if the process terminated normally by a call to _exit(2) or
exit(3).
And then to get the exit status:
WEXITSTATUS(status)
If WIFEXITED(status) is true, evaluates to the low-order 8 bits
of the argument passed to _exit(2) or exit(3) by the child.
For example:
int main(int argc, char **argv) {
pid_t pid;
int res;
pid = fork();
if (pid == 0) {
printf("child\n");
exit(1);
}
pid = wait(&res);
printf("raw res=%d\n", res);
if (WIFEXITED(res))
printf("exit status = %d\n", WEXITSTATUS(res));
return 0;
}
You can read more details in the wait(2) man page.
The status code contains various information about how the child process exited. Macros are provided to get information from the status code.
From wait(2) on linux:
If status is not NULL, wait() and waitpid() store status information in the int to which it points. This integer can be inspected with the following macros (which take the integer itself as an argu-
ment, not a pointer to it, as is done in wait() and waitpid()!):
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a
return statement in main(). This macro should be employed only if WIFEXITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a signal.
WTERMSIG(status)
returns the number of the signal that caused the child process to terminate. This macro should be employed only if WIFSIGNALED returned true.
WCOREDUMP(status)
returns true if the child produced a core dump. This macro should be employed only if WIFSIGNALED returned true. This macro is not specified in POSIX.1-2001 and is not available on some UNIX
implementations (e.g., AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif.
WIFSTOPPED(status)
returns true if the child process was stopped by delivery of a signal; this is possible only if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).
WSTOPSIG(status)
returns the number of the signal which caused the child to stop. This macro should be employed only if WIFSTOPPED returned true.
WIFCONTINUED(status)
(since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
SUGGESTION: try one of the following "Process Completion Status" macros:
http://www.gnu.org/software/libc/manual/html_node/Process-Completion-Status.html
EXAMPLE:
int status = 0;
..
int retval = wait (&status);
if (WIFEXITED(status))
printf("OK: Child exited with exit status %d.\n", WEXITSTATUS(status));
else
printf("ERROR: Child has not terminated correctly.\n");
From a existing question here, someone gave this example code:
int status;
child_pid = fork();
if (child_pid == 0) {
// in child; do stuff including perhaps exec
} else if (child_pid == -1) {
// failed to fork
} else {
if (waitpid(child_pid, &status, 0) == child_pid) {
// child exited or interrupted; now you can do something with status
} else {
// error etc
}
}
Could anyone explain to me what the second parameter of waitpid() is used for?
from man pages :
If status is not NULL, wait() and waitpid() store status infor-
mation in the int to which it points. This integer can be
inspected with the following macros (which take the integer
itself as an argument, not a pointer to it, as is done in wait()
and waitpid()!):
WIFEXITED(status)
returns true if the child terminated normally, that is,
by calling exit(3) or _exit(2), or by returning from
main().
WEXITSTATUS(status)
returns the exit status of the child. This consists of
the least significant 8 bits of the status argument that
the child specified in a call to exit(3) or _exit(2) or
as the argument for a return statement in main(). This
macro should only be employed if WIFEXITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a
signal.
WTERMSIG(status)
returns the number of the signal that caused the child
process to terminate. This macro should only be employed
if WIFSIGNALED returned true.
WCOREDUMP(status)
returns true if the child produced a core dump. This
macro should only be employed if WIFSIGNALED returned
true. This macro is not specified in POSIX.1-2001 and is
not available on some Unix implementations (e.g., AIX,
SunOS). Only use this enclosed in #ifdef WCOREDUMP ...
#endif.
WIFSTOPPED(status)
returns true if the child process was stopped by delivery
of a signal; this is only possible if the call was done
using WUNTRACED or when the child is being traced (see
ptrace(2)).
WSTOPSIG(status)
returns the number of the signal which caused the child
to stop. This macro should only be employed if WIF-
STOPPED returned true.
WIFCONTINUED(status)
(since Linux 2.6.10) returns true if the child process
was resumed by delivery of SIGCONT.
So it stores status of the "how the child terminated".
You can use the macros to investigate how exactly the child terminated, and you can define some actions depending to the child's termination status.
It is a bit-field for options, the only one available is WNOWAIT, which means to leave the child in a waitable state; a later wait call can be used to again retrieve the child status information.
See: http://linux.die.net/man/2/waitpid
pid = fork();
if(pid < 0)
{
printf("fork failed\n");
return -1;
}
else if(pid == 0)
{
sleep(5);
printf("Child process\n");
return 2;
}
else
{
printf("Parent process\n");
kill(pid, SIGKILL);
waitpid(pid, &ret, 0);
if(WIFEXITED(ret))
printf("Child process returned normally\n");
if(WIFSIGNALED(ret))
printf("Child process terminated by signal\n");
return 1;
}
As you can see that the return value can be used to check how a particular process terminated and take actions on the basis of that.
If you comment the kill line from the code, the child process will terminate properly.