Getting return value of external program [duplicate] - c

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);

Related

Fork and execlp, how to differentiate the status and print state accordingly

I am referring to this question - How to get the return value of a program ran via calling a member of the exec family of functions? from SO as I am trying to attempt similar actions.
Instead of the execl command, I am using execlp command. As my code, is supposed to take in a list of command line arguments, eg. ./myCode /bin/ls /bin/date in the event even if one of the argument is wrong, for example /bin/lsa, it is printing out the wrong line - Child Exit Code is 0.
Here is the code:
#include <stdio.h>
#include <stdlib.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)
{
execlp("/bin/lsa", "/bin/ls" ,(char *) NULL);
// error
printf("ERROR - Cannot run command\n");
}
else
{
printf("PID %d: waiting for child\n", getpid());
waitpid( child_pid, &statval, WUNTRACED);
if(WIFEXITED(statval))
printf("Child's exit code %d\n", WEXITSTATUS(statval));
else
printf("Child did not terminate with exit\n");
}
return 0;
}
And here is the terminal output:
119: I'm the parent !
PID 119: waiting for child
ERROR - Cannot run command
Child's exit code 0
What are some of the other ways that I can do to improve the last portion of the if-else code block? Using the example ./myCode /bin/lsa /bin/date, I am trying to achieve the following output:
Command /bin/lsa cannot be executed
<display output of /bin/date>
Command /bin/date is a success
After the child prints "ERROR - Cannot run command\n", it falls through to the return 0; statement, causing the process to exit with status code 0. You can return some other small positive value to change the exit code.
Running an unknown command in the Bash shell seems to set Bash's $? variable to 127, so perhaps that is a reasonable choice of return value.

waitpid stops waiting after signal is sent

I am currently working on a C project for university. Among other things I should signal the parent process using SIGUSR1.
The problem I'm facing at the moment is that I also need to wait for the child process to terminate so I can safely shut down everything in the end (removing shared Memory etc.).
At the moment I am using sigaction() to respond to the signal and waitpid() to wait for the child to terminate (that was the plan anyways ^^). But when I signal the parent using kill(), waitpid() stops waiting and runs the remainder of the parent even though the child is still running.
I feel like I'm missing something obvious but I can't figure it out.
Any help is greatly appreciated,
stay safe
Tim
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
void handle_sigusr1(int sig) {
printf("Recieved signal %i.\n", sig);
}
int main() {
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork:");
return EXIT_FAILURE;
}
else if (pid == 0) {
printf("Hello from the child.\n");
kill(getppid(), SIGUSR1);
sleep(3);
printf("Hello again from the child.\n");
return EXIT_SUCCESS;
}
else {
printf("Hello from the parent.\n");
struct sigaction sa;
sa.sa_handler = &handle_sigusr1;
sigaction(SIGUSR1, &sa, NULL);
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status))
printf("Exit status: %i\n", WEXITSTATUS(status));
printf("Finished waiting for child.\n");
return EXIT_SUCCESS;
}
}
Output:
Hello from the parent.
Hello from the child.
Recieved signal 10.
Exit status: 0
Finished waiting for child.
tim#schlepptop:signalTest$ Hello again from the child.
PS: WEXITSTATUS(status) is usually 0 but sometimes it's also something like 16 or 128.
Per POSIX waitpid() documentation:
RETURN VALUE
... If wait() or waitpid() returns due to the delivery of a signal to the calling process, -1 shall be returned and errno set to [EINTR]. ...
You need to check the return value:
int status
do
{
errno = 0;
int rc = waitpid(pid, &status, 0);
if ( rc != -1 )
{
break;
}
}
while ( errno == EINTR );

c fork() and kill() at the same time not working?

Main program: Start a certain amount of child processes then send SIGINT right away.
int main()
{
pid_t childs[CHILDS];
char *execv_argv[3];
int n = CHILDS;
execv_argv[0] = "./debugging_procs/wait_time_at_interrupt";
execv_argv[1] = "2";
execv_argv[2] = NULL;
for (int i = 0; i < n; i++)
{
childs[i] = fork();
if (childs[i] == 0)
{
execv(execv_argv[0], execv_argv);
if (errno != 0)
perror(strerror(errno));
_exit(1);
}
}
if (errno != 0)
perror(strerror(errno));
// sleep(1);
for (int i = 0; i < n; i++)
kill(childs[i], SIGINT);
if (errno != 0)
perror(strerror(errno));
// Wait for all children.
while (wait(NULL) > 0);
return 0;
}
Forked program: Wait for any signal, if SIGINT is sent, open a certain file and write SIGINT and the current pid to it and wait the amount specified of seconds (in this case, I send 2 from the main program).
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
void sigint_handler(int signum)
{
int fd = open("./aux/log1", O_WRONLY | O_APPEND);
char buf[124];
(void)signum;
sprintf(buf, "SIGINT %d\n", getpid());
write(fd, buf, strlen(buf));
close(fd);
}
int main(int argc, char **argv)
{
int wait_time;
wait_time = (argv[1]) ? atoi(argv[1]) : 5;
signal(SIGINT, &sigint_handler);
// Wait for any signal.
pause();
sleep(wait_time);
return 0;
}
The problem is, that the log file that the children should write, doesn't have n lines, meaning that not all children wrote to it. Sometimes nobody writes anything and the main program doesn't wait at all (meaning that sleep() isn't called in this case).
But if I uncomment sleep(1) in the main program, everything works just as I expected.
I suspect that the child processes don't get enough time to listen to SIGINT.
The program I'm working on is a task control and when I run a command like:
restart my_program; restart my_program I get an unstable behaviour. When I call restart, a SIGINT is sent, then a new fork() is called then another SIGINT is sent, just like the example above.
How can I make sure all children will parse SIGINT without the sleep(1) line? I'm testing my program if it can handle programs that don't exit right away after SIGINT is sent.
If I add for example, printf("child process started\n"); at the top of the child program, it doesn't get printed and the main program doesn't wait for anything, unless I sleep for a second. This happens even with only 1 child process.
Everything is working as it should. Some of your child processes get killed by the signal, before they set up the signal handler, or even before they start executing the child binary.
In your parent process, instead of just wait()ing until there are no more child processes, you could examine the identity and exit status of each of the processes reaped. Replace while (wait(NULL) > 0); with
{
pid_t p;
int status;
while ((p = wait(&status)) > 0) {
if (WIFEXITED(status))
printf("Child %ld exit status was %d.\n", (long)p, WEXITSTATUS(status));
else
if (WIFSIGNALED(status))
printf("Child %ld was killed by signal %d.\n", (long)p, WTERMSIG(status));
else
printf("Child %ld was lost.\n", (long)p);
fflush(stdout);
}
}
and you'll see that the "missing" child processes were terminated by the signals. This means that the child process was killed before it was ready to catch the signal.
I wrote my own example program pairs, with complete error checking. Instead of a signal handler, I decided to use sigprocmask() and sigwaitinfo(), just to show another way to do the same thing (and to not be limited to async-signal safe functions in a signal handler).
parent.c:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
const char *signal_name(const int signum)
{
static char buffer[32];
switch (signum) {
case SIGINT: return "INT";
case SIGHUP: return "HUP";
case SIGTERM: return "TERM";
default:
snprintf(buffer, sizeof buffer, "%d", signum);
return (const char *)buffer;
}
}
static int compare_pids(const void *p1, const void *p2)
{
const pid_t pid1 = *(const pid_t *)p1;
const pid_t pid2 = *(const pid_t *)p2;
return (pid1 < pid2) ? -1 :
(pid1 > pid2) ? +1 : 0;
}
int main(int argc, char *argv[])
{
size_t count, r, i;
int status;
pid_t *child, *reaped, p;
char dummy;
if (argc < 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s COUNT PATH-TO-BINARY [ ARGS ... ]\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "This program will fork COUNT child processes,\n");
fprintf(stderr, "each child process executing PATH-TO-BINARY.\n");
fprintf(stderr, "Immediately after all child processes have been forked,\n");
fprintf(stderr, "they are sent a SIGINT signal.\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (sscanf(argv[1], " %zu %c", &count, &dummy) != 1 || count < 1) {
fprintf(stderr, "%s: Invalid count.\n", argv[1]);
return EXIT_FAILURE;
}
child = malloc(count * sizeof child[0]);
reaped = malloc(count * sizeof reaped[0]);
if (!child || !reaped) {
fprintf(stderr, "%s: Count is too large; out of memory.\n", argv[1]);
return EXIT_FAILURE;
}
for (i = 0; i < count; i++) {
p = fork();
if (p == -1) {
if (i == 0) {
fprintf(stderr, "Cannot fork child processes: %s.\n", strerror(errno));
return EXIT_FAILURE;
} else {
fprintf(stderr, "Cannot fork child %zu: %s.\n", i + 1, strerror(errno));
count = i;
break;
}
} else
if (!p) {
/* Child process */
execvp(argv[2], argv + 2);
{
const char *errmsg = strerror(errno);
fprintf(stderr, "Child process %ld: Cannot execute %s: %s.\n",
(long)getpid(), argv[2], errmsg);
exit(EXIT_FAILURE);
}
} else {
/* Parent process. */
child[i] = p;
}
}
/* Send all children the INT signal. */
for (i = 0; i < count; i++)
kill(child[i], SIGINT);
/* Reap and report each child. */
r = 0;
while (1) {
p = wait(&status);
if (p == -1) {
if (errno == ECHILD)
break;
fprintf(stderr, "Error waiting for child processes: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
if (r < count)
reaped[r++] = p;
else
fprintf(stderr, "Reaped an extra child process!\n");
if (WIFEXITED(status)) {
switch (WEXITSTATUS(status)) {
case EXIT_SUCCESS:
printf("Parent: Reaped child process %ld: EXIT_SUCCESS.\n", (long)p);
break;
case EXIT_FAILURE:
printf("Parent: Reaped child process %ld: EXIT_FAILURE.\n", (long)p);
break;
default:
printf("Parent: Reaped child process %ld: Exit status %d.\n", (long)p, WEXITSTATUS(status));
break;
}
fflush(stdout);
} else
if (WIFSIGNALED(status)) {
printf("Parent: Reaped child process %ld: Terminated by %s.\n", (long)p, signal_name(WTERMSIG(status)));
fflush(stdout);
} else {
printf("Parent: Reaped child process %ld: Lost.\n", (long)p);
fflush(stdout);
}
}
if (r == count) {
/* Sort both pid arrays. */
qsort(child, count, sizeof child[0], compare_pids);
qsort(reaped, count, sizeof reaped[0], compare_pids);
for (i = 0; i < count; i++)
if (child[i] != reaped[i])
break;
if (i == count)
printf("Parent: All %zu child processes were reaped successfully.\n", count);
}
return EXIT_SUCCESS;
}
child.c:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
const char *signal_name(const int signum)
{
static char buffer[32];
switch (signum) {
case SIGINT: return "INT";
case SIGHUP: return "HUP";
case SIGTERM: return "TERM";
default:
snprintf(buffer, sizeof buffer, "%d", signum);
return (const char *)buffer;
}
}
int main(void)
{
const long mypid = getpid();
sigset_t set;
siginfo_t info;
int result;
printf("Child: Child process %ld started!\n", mypid);
fflush(stdout);
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGTERM);
sigprocmask(SIG_BLOCK, &set, NULL);
result = sigwaitinfo(&set, &info);
if (result == -1) {
printf("Child: Child process %ld failed: %s.\n", mypid, strerror(errno));
return EXIT_FAILURE;
}
if (info.si_pid == 0)
printf("Child: Child process %ld terminated by signal %s via terminal.\n", mypid, signal_name(result));
else
if (info.si_pid == getppid())
printf("Child: Child process %ld terminated by signal %s sent by the parent process %ld.\n",
mypid, signal_name(result), (long)info.si_pid);
else
printf("Child: Child process %ld terminated by signal %s sent by process %ld.\n",
mypid, signal_name(result), (long)info.si_pid);
return EXIT_SUCCESS;
}
Compile both using e.g.
gcc -Wall -O2 parent.c -o parent
gcc -Wall -O2 child.c -o child
and run them using e.g.
./parent 100 ./child
where the 100 is the number of child processes to fork, each running ./child.
Errors are output to standard error. Each line from parent to standard output begins with Parent:, and each line from any child to standard output begins with Child:.
On my machine, the last line in the output is always Parent: All # child processes were reaped successfully., which means that every child process fork()ed, was reaped and reported using wait(). Nothing was lost, and there were no issues with fork() and kill().
(Do note that if you specify more child processes than you are allowed to fork, the parent program does not consider that an error, and just uses the allowed number of child processes for the test.)
On my machine, forking and reaping 100 child processes is enough work for the parent process, so that every child process gets to the part where it is ready to catch the signal.
On the other hand, the parent can handle 10 child processes (running ./parent 10 ./child) so fast that every one of the child processes gets killed by the INT signal before they are ready to handle the signal.
Here is the output from a pretty typical case when running ./parent 20 ./child:
Child: Child process 19982 started!
Child: Child process 19983 started!
Child: Child process 19984 started!
Child: Child process 19982 terminated by signal INT sent by the parent process 19981.
Child: Child process 19992 started!
Child: Child process 19983 terminated by signal INT sent by the parent process 19981.
Child: Child process 19984 terminated by signal INT sent by the parent process 19981.
Parent: Reaped child process 19982: EXIT_SUCCESS.
Parent: Reaped child process 19985: Terminated by INT.
Parent: Reaped child process 19986: Terminated by INT.
Parent: Reaped child process 19984: EXIT_SUCCESS.
Parent: Reaped child process 19987: Terminated by INT.
Parent: Reaped child process 19988: Terminated by INT.
Parent: Reaped child process 19989: Terminated by INT.
Parent: Reaped child process 19990: Terminated by INT.
Parent: Reaped child process 19991: Terminated by INT.
Parent: Reaped child process 19992: Terminated by INT.
Parent: Reaped child process 19993: Terminated by INT.
Parent: Reaped child process 19994: Terminated by INT.
Parent: Reaped child process 19995: Terminated by INT.
Parent: Reaped child process 19996: Terminated by INT.
Parent: Reaped child process 19983: EXIT_SUCCESS.
Parent: Reaped child process 19997: Terminated by INT.
Parent: Reaped child process 19998: Terminated by INT.
Parent: Reaped child process 19999: Terminated by INT.
Parent: Reaped child process 20000: Terminated by INT.
Parent: Reaped child process 20001: Terminated by INT.
Parent: All 20 child processes were reaped successfully.
Of the 20 child processes, 16 were killed by INT signal before they executed the first printf() (or fflush(stdout)) line. (We could add a printf("Child: Child process %ld executing %s\n", (long)getpid(), argv[2]); fflush(stdout); to parent.c just before the execvp() line, to see if any of the child processes get killed before they execute at all.)
Of the four remaining child processes (19982, 19983, 19984, and 19992), one (19982) was terminated after the first printf() or fflush(), but before it managed to run setprocmask(), which blocks the signal and prepares the child for catching it.
Only those three remaining child processes (19983, 19984, and 19992) caught the INT signal sent by the parent process.
As you can see, just adding complete error checking, and adding sufficient output (and fflush(stdout); where useful, as standard output is buffered by default), lets you run several test cases, and construct a much better overall picture of what is happening.
The program I'm working on is a task control and when I run a command like: restart my_program; restart my_program I get an unstable behaviour. When I call restart, a SIGINT is sent, then a new fork() is called then another SIGINT is sent, just like the example above.
In that case, you are sending the signal before the new fork is ready, so the default disposition of the signal (Termination, for INT) defines what happens.
The solutions to this underlying problem vary. Note that it is at the core of many init system issues. It is easy to solve if the child (my_program here) co-operates, but difficult in all other cases.
One simple co-operation method is to have the child send a signal to its parent process, whenever it is ready for action. To avoid killing parent processes that are unprepared for such information, a signal that is ignored by default (SIGWINCH, for example) can be used.
The option of sleeping for some duration, so that the new child process has enough time to become ready for action, is a common, but pretty unreliable method of mitigating this issue. (In particular, the required duration depends on the child process priority, and the overall load on the machine.)
Try using the waitpid() command in the for loop. This way the next child will only write once the first child is done

System call fork() and execv function

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.

How to get the return value of a program ran via calling a member of the exec family of functions?

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);

Resources