I'm trying to run two executables consecutively using this c code:
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
fork();
execv("./prcs1", &argv[1]); // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
fork();
execv("./prcs2", argv);
printf("EXECV Failed\n");
}
The program exits after the first execv() call despite the fork, it never gets to the second execv(). I've tried calling wait() after the first fork but I'm not sure that's what it's missing.
Any ideas why control doesn't return to the parent after the child exits?
You need to understand how fork and execv work together.
fork() makes a duplicate of the current process, returning 0 to child, childpid to parent
fork() can fail, and returns -1 on failure, check for that
execv() replaces the duplicated parent process with a new process
typical fork/exec pairing replaces the child process with a new process
often you fork more than one child, and want them to run simultaneously,
however, you asked for them to run consecutively, that is one after another
thus, you need to wait for the first to complete before starting the second
thus you need to use some variant of wait(), example below uses waitpid() to wait for specific child
You need stdlib for exit (in case execv fails), and errno, to print the reason,
//I'm trying to run two executables consecutively using this c code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
You may want to examine the reason your child exited (core dump, signal, normal exit), thus I have added this function,
#include <sys/types.h>
#include <sys/wait.h>
//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 WIFSTOPPED returned true.
//WIFCONTINUED(status) (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
int
exitreason(pid_t cid, int status)
{
if( WIFEXITED(status) )
{
printf("child %d terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().\n",cid);
if( WEXITSTATUS(status) )
{
printf("child %d exit status %d. 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().\n",cid,WEXITSTATUS(status));
}
}
if( WIFSIGNALED(status) )
{
printf("child %d process was terminated by a signal.\n",cid);
if( WTERMSIG(status) )
{
printf("child %d signal %d that caused the child process to terminate.\n",cid,WTERMSIG(status));
}
if( WCOREDUMP(status) )
{
printf("child %d produced a core dump. WCOREDUMP() 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.\n",cid);
}
}
if( WIFSTOPPED(status) )
{
printf("child %d 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)).\n",cid);
if( WSTOPSIG(status) )
{
printf("child %d number of the signal which caused the child to stop.\n",cid);
}
}
if( WIFCONTINUED(status) )
{
printf("child %d process was resumed by delivery of SIGCONT.\n");
}
}
And here is your program annotated with comments explaining which sections of code are processed by the parent, and which by the child(ren).
int main (int argc, char *argv[])
{
char proc1[] = "/bin/echo"; //"./prcs1";
char proc2[] = "/bin/echo"; //"./prcs2";
pid_t cid1, cid2, cidX;
int status=0;
int waitoptions = 0;
//WNOHANG return immediately if no child has exited.
//WUNTRACED also return if a child has stopped (but not traced via ptrace(2)). Status for traced children which have stopped is provided even if this option is not specified.
//WCONTINUED also return if a stopped child has been resumed by delivery of SIGCONT.
int res;
if( (cid1 = fork()) == 0 ) //child1
{
printf("in child1\n");
if( (res = execv(proc1, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
{
printf("error: child1: %d exec failed %d\n", cid1, errno);
printf("error: cannot execv %s\n",proc1);
exit(91); //must exit child
}
}
else if( cid1 > 0 ) //cid>0, parent, waitfor child
{
cidX = waitpid(cid1, &status, waitoptions);
printf("child1: %d res %d\n", cid1, res);
exitreason(cid1, status);
}
else //cid1 < 0, error
{
printf("error: child1 fork failed\n");
}
if( (cid2 = fork()) == 0 ) //child2
{
printf("in child2\n");
if( (res = execv(proc2, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
{
printf("error: child2: %d exec failed %d\n", cid2, errno);
printf("error: cannot execv %s\n",proc2);
exit(92); //must exit child
}
}
else if( cid2 > 0 ) //cid>0, parent, waitfor child
{
cidX = waitpid(cid2, &status, waitoptions);
printf("child2: %d res %d\n", cid2, res);
exitreason(cid2, status);
}
else //cid2 < 0, error
{
printf("error: child2 fork failed\n");
}
}
You have a couple of problems. First, if you only want to run two programs, you only need to call fork() once. Then run one program in the parent process and one in the child. Second, you're constructing the argv array to be passed to execv incorrectly. The first entry should be the executable name. Do something like:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
pid_t i = fork();
if (i == 0)
{
execv("./prcs1", (char *[]){ "./prcs1", argv[1], NULL });
_exit(1);
}
else if (i > 0)
{
execv("./prcs2", (char *[]){ "./prcs2", argv[0], NULL });
_exit(2);
}
else
{
perror("fork failed");
_exit(3);
}
}
Note that this example does no error checking.
You haven't had much reading on fork() I guess.
when you call fork(), it creates a child process which will run the same code from fork.
fork() returns three kind of values
negative which shows an error
positive which says you are in parent process and value shows childprosess ID
zero which says you are in child process.
your code should look like this.
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
int ret = fork();
if(ret==0)
{
//child process
execv("./prcs1", &argv[1]); // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
printf("EXECV Failed from child\n");
}
else if(ret>0)
{
//parent process
execv("./prcs2", argv);
printf("EXECV Failed from parent\n");
}
else
{
//you will come here only if fork() fails.
printf("forkFailed\n");
}
return 0;
}
The exec family will only return if the call fails.
Since you do not check the return value of fork you will call execv in parent and child process.
Check the return value: if it is 0 you are in the child process, if it is greater than zero then you are in the parent process. Less than zero means the fork failed.
Related
I know that it is possible to read commands output with a pipe? But what about getting return value ? For example i want to execute:
execl("/bin/ping", "/bin/ping" , "-c", "1", "-t", "1", ip_addr, NULL);
How can i get returned value of ping command to find out if it returned 0 or 1?
Here is an example I wrote long time ago. Basically, after you fork a child process and you wait its exit status, you check the status using two Macros. WIFEXITED is used to check if the process exited normally, and WEXITSTATUS checks what the returned number is in case it returned normally:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int number, statval;
printf("%d: I'm the parent !\n", getpid());
if(fork() == 0)
{
number = 10;
printf("PID %d: exiting with number %d\n", getpid(), number);
exit(number) ;
}
else
{
printf("PID %d: waiting for child\n", getpid());
wait(&statval);
if(WIFEXITED(statval))
printf("Child's exit code %d\n", WEXITSTATUS(statval));
else
printf("Child did not terminate with exit\n");
}
return 0;
}
You can use waitpid to get the exit status of you child process as:
int childExitStatus;
waitpid( pID, &childExitStatus, 0); // where pID is the process ID of the child.
exec function familly does not return, the return int is here only when an error occurs at launch time (like not finding file to exec).
You have to catch return value from the signal sent to the process that forked before calling exec.
call wait() or waitpid() in your signal handler (well, you can also call wait() in your process without using any signal handler if it has nothing else to do).
Had trouble understanding and applying the existing answers.
In AraK's answer, if the application has more than one child process running, it is not possible to know which specific child process produced the exit status obtained. According the man page,
wait() and waitpid()
The wait() system call suspends execution of the calling process until one of its children terminates. The call wait(&status)
is equivalent to:
waitpid(-1, &status, 0);
The **waitpid()** system call suspends execution of the calling process until a **child specified by pid** argument has changed state.
So, to obtain the exit status of a specific child process we should rewrite the answer as :
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int number, statval;
int child_pid;
printf("%d: I'm the parent !\n", getpid());
child_pid = fork();
if(child_pid == -1)
{
printf("could not fork! \n");
exit( 1 );
}
else if(child_pid == 0)
{
execl("/bin/ping", "/bin/ping" , "-c", "1", "-t", "1", ip_addr, NULL);
}
else
{
printf("PID %d: waiting for child\n", getpid());
waitpid( child_pid, &statval, WUNTRACED
#ifdef WCONTINUED /* Not all implementations support this */
| WCONTINUED
#endif
);
if(WIFEXITED(statval))
printf("Child's exit code %d\n", WEXITSTATUS(statval));
else
printf("Child did not terminate with exit\n");
}
return 0;
}
Feel free to turn this answer to an edit of AraK's answer.
You can wait on the child process and get its exit status.
The system call is wait(pid), try to read about it.
Instead of exec family, you can use popen. Then read the output using fgets or fscanf.
char buff[MAX_BUFFER_SIZE];
FILE *pf = popen("your command", "r");
fscanf(pf, "%s", buff);
pclose(pf);
I have a function that forks a process, duplicates file descriptors for input and output buffers, and then runs execl on a command passed in via a string called cmd:
static pid_t
c2b_popen4(const char* cmd, int pin[2], int pout[2], int perr[2], int flags)
{
pid_t ret = fork();
if (ret < 0) {
fprintf(stderr, "fork() failed!\n");
return ret;
}
else if (ret == 0) {
/*
Assign file descriptors to child pipes (not shown)...
*/
execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
fprintf(stderr, "execl() failed!\n");
exit(EXIT_FAILURE);
}
else {
/*
Close parent read and write pipes (not shown)...
*/
return ret;
}
return ret;
}
Each of the cmd instances process my data correctly, so long as my test inputs are correct.
When bad data is passed to a child process, my parent program will run to completion and exit with a non-error status code of 0.
If I deliberately put in bad input — to purposefully try to get one of the cmd instances to fail in an expected way — I'd like to know how to capture the exit status of that cmd so that I can issue the correct error status code from the parent program, before termination.
How is this generally done?
You can get the exit status of the child via the first argument of wait(), or the second argument of waitpid(), and then using the macros WIFEXITED and WEXITSTATUS with it.
For instance:
pid_t ret = c2b_popen4("myprog", pin, pout, perr, 0);
if ( ret > 0 ) {
int status;
if ( waitpid(ret, &status, 0) == -1 ) {
perror("waitpid() failed");
exit(EXIT_FAILURE);
}
if ( WIFEXITED(status) ) {
int es = WEXITSTATUS(status);
printf("Exit status was %d\n", es);
}
}
A simplified working example:
failprog.c:
int main(void) {
return 53;
}
shellex.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t p = fork();
if ( p == -1 ) {
perror("fork failed");
return EXIT_FAILURE;
}
else if ( p == 0 ) {
execl("/bin/sh", "bin/sh", "-c", "./failprog", "NULL");
return EXIT_FAILURE;
}
int status;
if ( waitpid(p, &status, 0) == -1 ) {
perror("waitpid failed");
return EXIT_FAILURE;
}
if ( WIFEXITED(status) ) {
const int es = WEXITSTATUS(status);
printf("exit status was %d\n", es);
}
return EXIT_SUCCESS;
}
Output:
paul#thoth:~/src/sandbox$ ./shellex
exit status was 53
paul#thoth:~/src/sandbox$
waitpid() will block until the process with the supplied process ID exits. Since you're calling your function with a popen() name and passing pipes to it, presumably your child process doesn't terminate quickly, so that probably wouldn't be the right place to check it, if the call succeeded. You can pass WNOHANG as the third parameter to waitpid() to check if the process has terminated, and to return 0 if the child has not yet exited, but you have to be careful about when you do this, since you get no guarantees about which process will run when. If you call waitpid() with WNOHANG immediately after returning from c2b_popen4(), it may return 0 before your child process has had a chance to execute and terminate with an error code, and make it look as if the execution was successful when it's just about to not be successful.
If the process does die immediately, you'll have problems reading from and writing to your pipes, so one option would be to check waitpid() if you get an error from the first attempt to do that, to check if the read() or write() is failing because your child process died. If that turns out to be true, you can retrieve the exit status and exit your overall program then.
There are other possible strategies, including catching the SIGCHLD signal, since that'll be raised whenever one of your child processes dies. It would be OK, for instance, to call _exit() right from your signal handler, after waiting for the child process (calling waitpid() in a signal handler is also safe) and getting its exit status.
I'm completely new to C and learning about processes. I'm a little confused as to what the code below is actually doing, it's taken from Wikipedia but I've seen it in several books and am unsure as to why, for example, we do pid_t pid; then pid = fork();. My reading seem to suggest the child process returns a pid of 0, however, I thought the very original parent process will maintain the pid of 0 after seeing a tree with the root as pid 0.
What does, for example, pid = fork(); do to the parent? As doesn't it do the same thing for the child? And doesn't pid = fork(); put it into a loop as it will do this for each child?
Basically, could someone explain each step to me as if I were, say, five? Maybe younger? Thanks!
#include <stdio.h> /* printf, stderr, fprintf */
#include <sys/types.h> /* pid_t */
#include <unistd.h> /* _exit, fork */
#include <stdlib.h> /* exit */
#include <errno.h> /* errno */
int main(void)
{
pid_t pid;
/* Output from both the child and the parent process
* will be written to the standard output,
* as they both run at the same time.
*/
pid = fork();
if (pid == -1)
{
/* Error:
* When fork() returns -1, an error happened
* (for example, number of processes reached the limit).
*/
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
/* Child process:
* When fork() returns 0, we are in
* the child process.
*/
int j;
for (j = 0; j < 10; j++)
{
printf("child: %d\n", j);
sleep(1);
}
_exit(0); /* Note that we do not use exit() */
}
else
{
/* When fork() returns a positive number, we are in the parent process
* (the fork return value is the PID of the newly created child process)
* Again we count up to ten.
*/
int i;
for (i = 0; i < 10; i++)
{
printf("parent: %d\n", i);
sleep(1);
}
exit(0);
}
return 0;
}
After executing the fork() function, you have two processes, which both continue executing after the fork call. The only difference between the two processes is the return value of fork(). In the original process, the "parent", the return value is the process id (pid) of the child. In the new cloned process, the "child", the return value is 0.
If you wouldn't test the return value of fork(), both processes would be doing exactly the same.
NB: to understand why the fork() function is useful, you need to read what the exec() function is doing. This function loads a new process from disk, and replaces the caller process with the new process. The combination of fork() and exec() is actually the way to start a different process.
Upon successful completion, fork() (source):
shall return 0 to the child process
and shall return the process ID of the child process to the parent process.
The example you gave is well explained. However, I would like to precise that Both processes (parent and child) shall continue to execute from the fork() function.
if you would like to know the PID of the child (from the code of the child), use getpid API.
fork is a function that returns twice - once for the parent, once for the child.
For the child, it returns 0, for the parent the pid of the child, any positive number; for both processes, the execution continues after the fork.
The child process will run through the else if (pid == 0) block, while the parent will run the else block.
I am trying to code a program that traces itself for system calls. I am having a difficult time making this work. I tried calling a fork() to create an instance of itself (the code), then monitor the resulting child process.
The goal is for the parent process to return the index of every system call made by the child process and output it to the screen. Somehow it is not working as planned.
Here is the code:
#include <unistd.h> /* for read(), write(), close(), fork() */
#include <fcntl.h> /* for open() */
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
pid_t child;
long orig_eax;
child = fork();
if (0 == child)
{
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
if (argc != 3) {
fprintf(stderr, "Usage: copy <filefrom> <fileto>\n");
return 1;
}
int c;
size_t file1_fd, file2_fd;
if ((file1_fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[1]);
return 1;
}
if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[2]);
return 1;
}
while (read(file1_fd, &c, 1) > 0)
write(file2_fd, &c, 1);
}
else
{
wait(NULL);
orig_eax = ptrace (PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL);
printf("copy made a system call %ld\n", orig_eax);
ptrace(PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
This code was based on this code:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h> /* For constants
ORIG_EAX etc */
int main()
{
pid_t child;
long orig_eax;
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl("/bin/ls", "ls", NULL);
}
else {
wait(NULL);
orig_eax = ptrace(PTRACE_PEEKUSER,
child, 4 * ORIG_EAX,
NULL);
printf("The child made a "
"system call %ld\n", orig_eax);
ptrace(PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
The output of this one is:
The child made a system call 11
which is the index for the exec system call.
According to the man pages for wait():
All of these system calls are used to wait for state changes in a child
of the calling process, and obtain information about the child whose
state has changed. A state change is considered to be: the child terminated;
the child was stopped by a signal; or the child was resumed by
a signal.
The way I understand it is that every time a system call is invoked by a user program, the kernel will first inspect if the process is being traced prior to executing the system call routine and pauses that process with a signal and returns control to the parent. Wouldn't that be a state change already?
The problem is that when the child calls ptrace(TRACEME) it sets itself up for tracing but doesn't actually stop -- it keeps going until it calls exec (in which case it stops with a SIGTRAP), or it gets some other signal. So in order for you to have the parent see what it does WITHOUT an exec call, you need to arrange for the child to receive a signal. The easiest way to do that is probably to have the child call raise(SIGCONT); (or any other signal) immediately after calling ptrace(TRACEME)
Now in the parent you just wait (once) and assume that the child is now stopped at a system call. This won't be the case if it stopped at a signal, so you instead need to call wait(&status) to get the child status and call WIFSTOPPED(status) and WSTOPSIG(status) to see WHY it has stopped. If it has stopped due to a syscall, the signal will be SIGTRAP.
If you want to see multiple system calls in the client, you'll need to do all of this in a loop; something like:
while(1) {
wait(&status);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
// stopped before or after a system call -- query the child and print out info
}
if (WIFEXITED(status) || WIFSIGNALED(status)) {
// child has exited or terminated
break;
}
ptrace(PTRACE_SYSCALL, childpid, 0, 0); // ignore any signal and continue the child
}
Note that it will stop TWICE for each system call -- once before the system call and a second time just after the system call completes.
you are basically trying to write strace binary in linux, which traces the system calls of the process. Linux provides ptrace(2) system call for this. ptrace system call takes 4 arguement and the first arguement tells what you need to do. OS communicates with the parent process with signals and child process is stopped by sending SIGSTOP. broadly you need to follow below steps.
if(fork() == 0 )
{
//child process
ptrace(PTRACE_TRACEME, 0,0, 0);
exec(...);
}
else
{
start:
wait4(...);
if (WIFSIGNALED(status)) {
//done
}
if (WIFEXITED(status)) {
//done
}
if(flag == startup)
{
flag = startupdone;
ptrace(PTRACE_SYSCALL, pid,0, 0) ;
goto start;
}
if (if (WSTOPSIG(status) == SIGTRAP) {) {
//extract the register
ptrace(PTRACE_GETREGS,pid,(char *)®s,0)
}
Note the register reading and interpretation will depend on your architecture. The above code is just an example to get it right you need to dig deeper. have a look at strace code for further understanding.
In your parent how many calls do you want to monitor? If you want more than one you're going to need some kind of loop.
Note the line in the example, it's important:
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
Looking at the man page the child needs to either do a PTRACE_TRACEME and an exec, or the parent needs to trace using PTRACE_ATTACH. I don't see either in your code:
The parent can initiate a trace by calling fork(2) and having the resulting child do a PTRACE_TRACEME, followed (typically) by an exec(3). Alternatively, the parent may commence trace of an existing process using PTRACE_ATTACH.
Just putting together what Chris Dodd said:
#include <unistd.h> /* for read(), write(), close(), fork() */
#include <fcntl.h> /* for open() */
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
pid_t child;
int status;
long orig_eax;
child = fork();
if (0 == child)
{
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
raise(SIGCONT);
if (argc != 3) {
fprintf(stderr, "Usage: copy <filefrom> <fileto>\n");
return 1;
}
int c;
size_t file1_fd, file2_fd;
if ((file1_fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[1]);
return 1;
}
if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[2]);
return 1;
}
while (read(file1_fd, &c, 1) > 0)
write(file2_fd, &c, 1);
}
else
{
while(1){
wait(&status);
if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP){
orig_eax = ptrace(PTRACE_PEEKUSER, child, sizeof(long) * ORIG_EAX, NULL);
printf("copy made a system call %ld\n", orig_eax);
}
if(WIFEXITED(status) || WIFSIGNALED(status)){
break;
}
ptrace(PTRACE_SYSCALL, child, 0, 0);
}
}
return 0;
}
I know that it is possible to read commands output with a pipe? But what about getting return value ? For example i want to execute:
execl("/bin/ping", "/bin/ping" , "-c", "1", "-t", "1", ip_addr, NULL);
How can i get returned value of ping command to find out if it returned 0 or 1?
Here is an example I wrote long time ago. Basically, after you fork a child process and you wait its exit status, you check the status using two Macros. WIFEXITED is used to check if the process exited normally, and WEXITSTATUS checks what the returned number is in case it returned normally:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int number, statval;
printf("%d: I'm the parent !\n", getpid());
if(fork() == 0)
{
number = 10;
printf("PID %d: exiting with number %d\n", getpid(), number);
exit(number) ;
}
else
{
printf("PID %d: waiting for child\n", getpid());
wait(&statval);
if(WIFEXITED(statval))
printf("Child's exit code %d\n", WEXITSTATUS(statval));
else
printf("Child did not terminate with exit\n");
}
return 0;
}
You can use waitpid to get the exit status of you child process as:
int childExitStatus;
waitpid( pID, &childExitStatus, 0); // where pID is the process ID of the child.
exec function familly does not return, the return int is here only when an error occurs at launch time (like not finding file to exec).
You have to catch return value from the signal sent to the process that forked before calling exec.
call wait() or waitpid() in your signal handler (well, you can also call wait() in your process without using any signal handler if it has nothing else to do).
Had trouble understanding and applying the existing answers.
In AraK's answer, if the application has more than one child process running, it is not possible to know which specific child process produced the exit status obtained. According the man page,
wait() and waitpid()
The wait() system call suspends execution of the calling process until one of its children terminates. The call wait(&status)
is equivalent to:
waitpid(-1, &status, 0);
The **waitpid()** system call suspends execution of the calling process until a **child specified by pid** argument has changed state.
So, to obtain the exit status of a specific child process we should rewrite the answer as :
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int number, statval;
int child_pid;
printf("%d: I'm the parent !\n", getpid());
child_pid = fork();
if(child_pid == -1)
{
printf("could not fork! \n");
exit( 1 );
}
else if(child_pid == 0)
{
execl("/bin/ping", "/bin/ping" , "-c", "1", "-t", "1", ip_addr, NULL);
}
else
{
printf("PID %d: waiting for child\n", getpid());
waitpid( child_pid, &statval, WUNTRACED
#ifdef WCONTINUED /* Not all implementations support this */
| WCONTINUED
#endif
);
if(WIFEXITED(statval))
printf("Child's exit code %d\n", WEXITSTATUS(statval));
else
printf("Child did not terminate with exit\n");
}
return 0;
}
Feel free to turn this answer to an edit of AraK's answer.
You can wait on the child process and get its exit status.
The system call is wait(pid), try to read about it.
Instead of exec family, you can use popen. Then read the output using fgets or fscanf.
char buff[MAX_BUFFER_SIZE];
FILE *pf = popen("your command", "r");
fscanf(pf, "%s", buff);
pclose(pf);