Multiprocess parent return value - c

Im wondering about the nature of the variable status and when its returned in a function.
Ive set my function to get an error, but if I dont do return status >> 8(127) and instead do return status, I get a return value of 0.
Ive used return WEXITSTATUS (status) in the past and itd return the correct status number.
My questions are if WEXITSTATUS actually does the operation status >> 8?
And when doing Multiprocessing and the parent process exists properly is it better to verify with WIFEXITED(status) then return WEXITSTATUS (status) rather than doing what I do?
int main {
int status;
int filedes[2];
pid_t pid_enfant;
pipe(filedes);
if (pid_child == 0) {
...
char *tab[] = {"/bin/bash", "-c", arg[1], NULL};
execv("/bin/bash", arg[1]);
return 1;
} else {
...
pid_t pid_child = wait(&status);
return status >> 8; -- // return this vs this below
//if (WIFEXITED(status) && pid_valide == pid_child)
//return WEXITSTATUS (status);
}
}

To answer your your question regarding WEXITSTATUS, the answer is yes; it is meant to shift the status down by 8 bits.
WEXITSTATUS(wstatus)
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.
Further, it explicitly states that the value of WEXITSTATUS(wstatus) is only valid if WIFEXITED(wstatus) is non-zero. So for your code to be correct with this specification, you should have
pid_t pid_child = wait(&status);
if (WIFEXITED(status))
{
return WEXITSTATUS(status);
}
else
{
// child did not terminate normally
}
As to why you should check this, here's a toy example:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int signal = /* choose your favourite signal, or 0 */;
switch (fork())
{
case -1:
perror("fork");
return -1;
case 0:
if (signal) { raise(signal); }
return 0;
default:
{
int status;
pid_t child = wait(&status);
printf("child=%d, status=%04x\n", child, status);
if (WIFEXITED(status))
{
puts("good exit");
return WEXITSTATUS(status);
}
else
{
puts("bad exit");
return -1;
}
}
break;
}
}
If we do not raise anything in the child and get a clean exit, we'll see child=..., status=0000 in the parent, and would take the 'good exit' branch returning 0, as expected. However, if we raise something like SIGSEGV in the child, then the parent will get child=..., status=008b. Now, if you blindly did status >> 8, then your parent would return 0 just like the 'good exit' path, but clearly the child did not exit cleanly.

Related

fork - Can I exit from parent?

I have written a code which will call exec as shown below. But if I call isValid from main, both child and parent process are returning and I am getting the output twice.
I want to get the out of the exec and want to check the return value in main only once. which process I need to exit inorder to make this work properly?
int isValid(void)
{
int number, statval;
int child_pid;
child_pid = fork();
if(child_pid == -1) { printf("Could not fork! \n"); exit( 1 ); }
else if(child_pid == 0)
{
execl(...); // Child
}
else
{
// Parent
waitpid( child_pid, &statval, WUNTRACED );
if(WIFEXITED(statval))
{
if (WEXITSTATUS(statval) == 0)
return 1;
else
return 0;
}
else
printf("Child did not terminate with exit\n");
}
return 0;
}
int main(void)
{
if (isValid())
{
printf("Valid\n");
}
else
{
printf("Invalid\n");
}
}
The doubled output may occur when the execl fails. The code above does not check the execl return value. Actually the execl returns only in case of failure so there is no need to check the returned value but it is necessary to handle error anyway.
EDIT:
If the exec fails then:
Child's isValid() returns 0 at the end of the function and the main prints "Invalid"
Parent waits for the child exit and then WIFEXITED is true because child exits and WEXITSTATUS is 0 because the child exits normally. Parent's isValid returns 1 and "Valid" is printed.
#include <sys/shm.h>
int *tabPID;
int isValid(void)
{
int number, statval;
if(fork() == 0){
tabPID[1] = getpid();
execl(...); // Child
return -1;
}
// Parent
tabPID[0]=getpid();
usleep(10);//as Basile Starynkevitch suggests
waitpid(tabPID[1], &statval, WUNTRACED );
if(WIFEXITED(statval))
{
if (WEXITSTATUS(statval) == 0)
return 1;
else
return 0;
}
else
printf("Child did not terminate with exit\n");
return 0;
}
int main(void)
{
shmId = shmget(1234, 2*sizeof(int), IPC_CREAT|0666);
tabPID = shmat(shmId, NULL, 0);
if (isValid())
{
printf("Valid\n");
}
else
{
printf("Invalid\n");
}
}
You probably should do some tiny things (perhaps some usleep(3) for a few milliseconds) after the fork but before the waitpid to have some real chance to get the waitpid(2) call succeed. Otherwise, it could happen that the other process won't be scheduled to run.
BTW, you should test the return value from waitpid, .e.g. code
statval = 0;
pid_t wpid = waitpid(child_pid, &statval, WUNTRACED );
if (wpid>0) {
assert (wpid == child_pid);
if (WIFEXITED(statval)) {
if (WEXITSTATUS(statval) == 0)
return 1;
At last, regarding the title of your question, read job control wikipage, read several chapters of Advanced Linux Programming, and consider using daemon(3)
Also, just after the execl be sure to put
perror("execl");
exit(EXIT_FAILURE);
to handle the rare case of execl failure.

How to create a program that reads the last commands exit status?

In Linux C, how do you read the last programs exit status.
For example:
true; echo $?
Will show a 0 for success. But I'd like to replace that with a C program:
true; ./echo_exit_status
How/where is the last exit code $? available to a C program?
The last command's exit status is not accessible to a subsequently-executed program (absent insanely-horrible hackery -- attaching to the parent shell with a debugger or somesuch).
You could write a shell function or helper that exported this value into the environment -- but no solution is possible which does not require the shell's involvement.
You'd have to know the pid but otherwise it's http://linux.die.net/man/2/waitpid
More info from the man page
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.
Here is an example from the
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status)); //this line will return the exit status, whether it was 1 or 0
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}

waitpid with execl used in child returns -1 with ECHILD?

When do I need to use waitpid if I am using execl in a child process which may take time to finish?
When I use waitpid in the parent, it tells me that the child is running as the return value from waitpid is 0. However, if I call waitpid after some time in another function, it returns -1 with errno set to ECHILD. When should I use waitpid if I am not sure whether the child has completed or not?
//pid_t Checksum_pid = fork();
Checksum_pid = fork();
if (Checksum_pid == 0)
{
execl(path, name, argument as needed, ,NULL);
exit(EXIT_SUCCESS);
}
else if (Checksum_pid > 0)
{
pid_t returnValue = waitpid(Checksum_pid, &childStatus, WNOHANG);
if ( returnValue > 0)
{
if (WIFEXITED(childStatus))
{
printf("Exit Code: _ WEXITSTATUS(childStatus)") ;
}
}
else if ( returnValue == 0)
{
//Send positive response with routine status running (0x03)
printf("Child process still running") ;
}
else
{
if ( errno == ECHILD )
{
printf(" Error ECHILD!!") ;
}
else if ( errno == EINTR )
{
// other real errors handled here.
printf(" Error EINTR!!") ;
}
else
{
printf("Error EINVAL!!") ;
}
}
}
else
{
/* Fork failed. */
printf("Fork Failed") ;
}
If the signal SIGCHLD is ignored (which is the default) and you skip WNOHANG as mentioned by Jonathan, waitpid will hang until the child exits and then fail with code ECHILD. I encountered this myself in a scenario where the parent process simply should wait for the child to finish and it seemed a bit overkill to register a handler for SIGCHLD. The natural follow-up question would be "Is it is OK to treat an ECHILD as an expected event in this case, or am I always supposed to write a handler for SIGCHLD?",
but for that I don't have an answer.
From the documentation for waitpid(2):
ECHILD
(for waitpid() or waitid()) The process specified by pid (waitpid())
or idtype and id (waitid()) does not exist or is not a child of the
calling process. (This can happen for one's own child if the action
for SIGCHLD is set to SIG_IGN. See also the Linux Notes section about
threads.)
and further down
POSIX.1-2001 specifies that if the disposition of SIGCHLD is set to
SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD (see
sigaction(2)), then children that terminate do not become zombies and
a call to wait() or waitpid() will block until all children have
terminated, and then fail with errno set to ECHILD. (The original
POSIX standard left the behavior of setting SIGCHLD to SIG_IGN
unspecified. Note that even though the default disposition of SIGCHLD
is "ignore", explicitly setting the disposition to SIG_IGN results in
different treatment of zombie process children.) Linux 2.6 conforms to
this specification. However, Linux 2.4 (and earlier) does not: if a
wait() or waitpid() call is made while SIGCHLD is being ignored, the
call behaves just as though SIGCHLD were not being ignored, that is,
the call blocks until the next child terminates and then returns the
process ID and status of that child.
See also this answer.
If you wait with WNOHANG, then you won't get any useful status unless your child has already died — and it may not even have got going yet (it could still be waiting for the executable to be loaded from disk when the parent executes the waitpid()).
If you want to know that the child has finished, don't use WNOHANG — use 0 for the third argument unless you want to know about untraced or continued processes. This will wait until the process identified by Checksum_pid exits, or the system loses track of it by some mysterious means (which I've never seen happen).
This code produces Exit Code: 0 as the output:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t Checksum_pid = fork();
if (Checksum_pid < 0)
printf("Fork Failed\n");
else if (Checksum_pid == 0)
{
execl("/bin/sleep", "/bin/sleep", "2", NULL);
exit(EXIT_FAILURE);
}
else
{
int childStatus;
pid_t returnValue = waitpid(Checksum_pid, &childStatus, 0);
if (returnValue > 0)
{
if (WIFEXITED(childStatus))
printf("Exit Code: %d\n", WEXITSTATUS(childStatus));
else
printf("Exit Status: 0x%.4X\n", childStatus);
}
else if (returnValue == 0)
printf("Child process still running\n");
else
{
if (errno == ECHILD)
printf(" Error ECHILD!!\n");
else if (errno == EINTR)
printf(" Error EINTR!!\n");
else
printf("Error EINVAL!!\n");
}
}
return 0;
}
It is very similar to your code; I've merely moved the check for fork() failing to the top. I'd still prefer to get rid of the 'bushy trees' of if statements, but it isn't critical. What happens when you run this code? What do you have to change to get the ECHILD error (can you change it so that you get the ECHILD error)?
When you've managed to get code based off this to reproduce the problem, we can work out why you get that behaviour.
Tested on Mac OS X 10.9.2 Mavericks with GCC 4.8.2, and also Ubuntu 13.10 with GCC 4.8.1 (I needed to add -D_XOPEN_SOURCE=700 to get it to compile with my stringent compilation flags; Mac OS X managed without that), but I don't expect to get different results elsewhere.
int start(int Area)
{
int childStatus;
pid_t Checksum_pid = fork();
if(Checksum_pid < 0)
{
/* Fork failed. */
printf(" Fork Failed") ;
}
else if (Checksum_pid == 0)
{
for (int i = 0; i<5; i++)
{
if ( g_area[i] == Area)
{
execl(ScriptPath, ScriptName, NULL);
}
}
exit(EXIT_FAILURE);
}
else
{
/* This is the parent process. */
pid_t returnValue = waitpid(Checksum_pid, &childStatus, 0);
if ( returnValue > 0)
{
// Check if child ended normally
printf("WAITPID Successful") ;
if (WIFEXITED(childStatus))
{
printf("Exit Code: _ WEXITSTATUS(childStatus)");
}
}
else if ( returnValue == 0)
{
printf("Child process still running") ;
}
else
{
if ( errno == ECHILD )
{
printf("Error ECHILD!!") ;
}
else if ( errno == EINTR )
{
printf("Error EINTR!!") ;
}
else
{
printf(" Error EINVAL!!") ;
}
retCode = FAILED;
}
}
}

More Information on Child Process Termination?

I googled for answer but all the threads I found seemed to suggest using an alternative way to terminate a child process: the _Exit() function.
I wonder if using "return 0;" truly terminate the child process? I tested that in my program (I have waitpid() in the parent process to catch the termination of the child process), and it seemed to work just fine.
So can someone please confirm on this question? Does a return statement truly terminate a process like the exit function or it simply sends a signal indicating the calling process is "done" while the process is actually still running?
Thanks in advance,
Dan
Sample Code:
pid = fork()
if (pid == 0) // child process
{
// do some operation
return 0; // Does this terminate the child process?
}
else if (pid > 0) // parent process
{
waitpid(pid, &status, 0);
// do some operation
}
Using the return statement inside the main function will immediately terminate the process and return the value specified. The process is terminated completely.
int main (int argc, char **argv) {
return 2;
return 1;
}
This program never reaches the second return statement, and the value 2 is returned to the caller.
EDIT - Example from when the fork happens inside another function
However if the return statement is not inside the main function, the child process will not terminate until it has reached down into main() again. The code below will output:
Child process will now return 2
Child process returns to parent process: 2
Parent process will now return 1
Code (tested on Linux):
pid_t pid;
int fork_function() {
pid = fork();
if (pid == 0) {
return 2;
}
else {
int status;
waitpid (pid, &status, 0);
printf ("Child process returns to parent process: %i\n", WEXITSTATUS(status));
}
return 1;
}
int main (int argc, char **argv) {
int result = fork_function();
if (pid == 0) {
printf ("Child process will now return %i\n", result);
}
else {
printf ("Parent process will now return %i\n", result);
}
return result;
}

how can I get the return value of a program executed by exec? [duplicate]

This question already has answers here:
How to get the return value of a program ran via calling a member of the exec family of functions?
(6 answers)
Closed 8 years ago.
I have this c code:
if(fork()==0){
execl("/usr/bin/fsck", "fsck", "/dev/c0d0p1s0", NULL);
}
it calls execl to run fsck for checking the filesystem /dev/c0d0p1s0.
My question is: how can I get the return value of fsck?
I need the return value of fsck to check whether the file system is consistence or not.
Thank you.
Have the parent process wait for the child to exit:
pid_t pid = fork();
if (pid == -1) {
// error, no child created
}
else if (pid == 0) {
// child
}
else {
// parent
int status;
if (waitpid(pid, &status, 0) == -1) {
// handle error
}
else {
// child exit code in status
// use WIFEXITED, WEXITSTATUS, etc. on status
}
}
You must call wait() or waitpid() in the parent process and it will give you the exit status of the program executed by execl(). Not calling one of these will make the child process remain a zombie when it terminates, i.e. a process that is dead but stays in the process table because its parent wasn't interested in its return code.
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
...
pid_t pid;
int status;
if ((pid = fork()) == 0) {
/* the child process */
execl(..., NULL);
/* if execl() was successful, this won't be reached */
_exit(127);
}
if (pid > 0) {
/* the parent process calls waitpid() on the child */
if (waitpid(pid, &status, 0) > 0) {
if (WIFEXITED(status) && !WEXITSTATUS(status)) {
/* the program terminated normally and executed successfully */
} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
if (WEXITSTATUS(status) == 127) {
/* execl() failed */
} else {
/* the program terminated normally, but returned a non-zero status */
switch (WEXITSTATUS(status)) {
/* handle each particular return code that the program can return */
}
}
} else {
/* the program didn't terminate normally */
}
} else {
/* waitpid() failed */
}
} else {
/* failed to fork() */
}
The _exit() call in the child is to prevent it from continuing execution in case execl() fails. Its return status (127) is also necessary to distinguish the case of an eventual execl() failure in the parent.

Resources