Return status of execve - c

I want to send exit status 0 from the execve process to the process which started it.
Because on Success execve never returns, So I am not able to do anything after that. But I want if execve ran successful.

You can verify that exec succeeded using FD_CLOEXEC:
create a pipe.
fork.
in the child, close the read end of the pipe and set the FD_CLOEXEC flag on the write end of the pipe. Then proceed with exec. If exec succeeds, the pipe will be automatically closed due to FD_CLOEXEC. If exec fails, write a byte to the pipe and exit.
in the parent, close the write end of the pipe and read from the read end. If you read 0 bytes (EOF), it means that exec succeeded. If you read a byte in the pipe, it means that exec failed.
The data written over the pipe in case of failure can be used to transmit error information, such as value of errno after exec.
The code, with error checking omitted for brevity, would look like this:
int pipe_fds[2];
pipe(pipe_fds);
if (!fork()) {
close(pipe_fds[0]);
fcntl(pipe_fds[1], F_SETFD, F_CLOEXEC);
execve(...);
write(pipe_fds[1], "", 1);
_exit(1);
}
else {
int n;
char out;
close(pipe_fds[1]);
n = read(pipe_fds[0], &out, 1);
if (n == 0)
printf("exec successful\n");
else
printf("exec failed\n");
close(pipe_fds[0]);
}
Note that this technique can be unsafe if other threads may exec their own processes in parallel. The issue is that there is a delay between when the pipe is created and when the close-on-exec flag gets set. If an unrelated thread forks and execs during that critical window, the child will inherit pipe_fds[1] and won't close it, causing the parent to hang. This can be fixed using the Linux-specific pipe2 call which allows atomically creating the pipe with the close-on-exec flag set.

to wait you process launched by fork() finish, you can use wait():
/* parent */
int status;
while (wait(&status) != uproc.pid) {
printf("waiting for child to exit");
}
and based on this question
The exit status of the child is provided by the wait function, in the status variable.
You get the exit status by using the WEXITSTATUS macro, but only if the program exited normally (i.e. called exit or returned from its main function):
if (WIFEXITED(status))
printf("Child exit status: %d\n", WEXITSTATUS(status));
else
printf("Child exited abnormally\n");

Related

waitpid not returning after child has exited

Using a fairly standard fork process:
int pipe_to_child[2];
int pipe_from_child[2];
int child_exit_status = -1;
pid_t child_pid = fork();
if (child_pid == 0) {
close(pipe_from_child[0]); // close their read end
close(pipe_to_child[1]); // Close their write end
dup2(pipe_to_child[0], STDIN_FILENO); // Tie the in pipe to stdin
dup2(pipe_from_child[1], STDOUT_FILENO); // Tie stdout to the out pipe
// Run the child process
execve(file_to_run, argv_for_prog, env_for_prog);
}
else {
close(pipe_from_child[1]); // close their write end
close(pipe_to_child[0]); // Close their read end
if (input_to_prog != NULL) write(pipe_to_child[1], input_to_prog, strlen(input_to_prog)); // Send the stdin stuff
close(pipe_to_child[1]); // Done so send EOF
// Wait for the child to end
waitpid(child_pid, &child_exit_status, 0);
// Do post end-of-child stuff
}
This generally works as expected.
However, when the child process, a shell script, sets a further process off in the background. Even though the child process then exits (and is no longer listed by ps), the waitpid doesn't return.
The script is this case is meant to start inadyn-mt (a DDNS updater) running in the background.
#!/bin/sh
inadyn-mt --background
(If I put an & after inadyn-mt it makes no difference)
It turns out that the issue is that the pipes don't get closed. Although the child process exits fine, because it has spawned a further process, this process (even though it doesn't want them) is tied to the pipes to the child's stdin and stdout. The solution I used was to not set up the pipes when I was going to spin off a child from the child.

Network Programming in C with execve system calls

I am trying to create a simple client/server program that allows the client to connect to the server using a TCP socket and then allows the user to issue system calls form the client side to the server side and return the reply to the user. For example:
Client issues: ls
Server will find ls in /usr/bin or w/e and then execute it using execve()
I will also have something liks lls, or lmkdir, ect..which will issue the system calls on the client side.
The problem is my execve() is not appearing to run correctly because 'ls' or any other command is not actually being called. I have done this same kind of program before with only a local side (no server or anything) and execve() worked fine. Here is some code:
pid = fork();
if(pid){ // Child
printf("child wait");
pid = wait(&status);
printf("Child dead\n");
}else{ // Parent
if(execPath){
execve(execPath, arglist, env);
printf("Command Complete\n");
}
}
For some reason the printfs in the child section of the PID statement are not executing at all. I do not think the system is actually ever forking a process. Is there something special I would have to do to make this work since it is a client/server type of program or should it work exactly the same?
Thanks
exactly, execve does not fork. It replaces current image with the one specified as its argument and starts from its start (i.e. main()). It never returns to your origial program.
You probably want to use system() in your use case.
There are several problems in the code:
fork() returns pid for the parent and zero for the child. So parent runs the true branch of the if. And child runs the else branch. Swap those comments.
The stdout is line buffered. Add new line (\n) to printf which is before the wait. Or else you don't see the printout before waiting is done and 2nd printf is under call.
Be sure that child will exit also in error cases, or else the child will run the code of parent, and parent is still waiting exit of the child.
execve does not return if it success. It will return, if it fails.
So, fixed code could be something like that:
pid = fork();
if(pid){ // Parent
printf("child wait\n");
pid = waitpid(pid, &status, 0);
printf("Child dead\n");
}else{ // Child
if(execPath){
execve(execPath, arglist, env);
printf("execve failed!\n");
}
_exit(1);
}
Or you could use system(3).
Since the child process has not spawned any children of its own, the wait() call is unlikely to return without some other external event (like a signal interrupting the call). You should have the parent wait on the child process instead.
Note that fork() may fail, and you should account for that. Also note that if execve succeeds, it won't return. So, the print statement after it should indicate failure if it is to print anything at all.
Using system() probably would not save you the fork, since you are likely to want the output of the command to be directed to the socket associated with the connected client. But, your code is missing the steps that would allow the output to flow to the client.
switch ((pid = fork())) {
case -1: /* todo: handle error */
break;
case 0: /* child */
dup2(socket, 0); /* todo: check return value */
dup2(socket, 1); /* todo: check return value */
dup2(socket, 2); /* todo: check return value */
close(socket); /* todo: check return value */
execve(...);
/* todo: handle failure */
exit(EXIT_FAILURE);
default: /* parent */
if (pid != waitpid(pid, 0, 0)) {
/* todo: handle error */
}
}

Input redirection problem while using execvp?

I have Implemented a simple program which simulates $ls -l | wc -c command execution using simple pipes and execvp calls.
Now After redirecting stdin and stdout ,when executes the program , shell prompt disappears and it waits for the enter key to be pressed.
Any way of solving this issue . Plz criticize my code also..
Thanks
/* Create pipe */
ret_val=pipe(pipe_fd);
/*Error check */
if(ERROR==ret_val)
{
perror("Pipe creation error \n");
_exit(FAILURE);
}
/*Fork First Child */
pid_one = fork() ;
if( 0 == pid_one ) /*child process block */
{
/* First sub process */
/*printf("First sub process is %d \n",getpid());*/
/* redirect stdout to pipe's write end for sub process one*/
dup2(pipe_fd[1],1);
/*close pipe read end */
close(pipe_fd[0]);
execvp(cmd_one_tokens[0],cmd_one_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
//exit(10);
}
else /*main process block */
{
/*printf(" Main process is %d \n",getpid());*/
/*Wait for first sub process to finish */
//wait(&status);
/*printf("Exit status of first child is %d \n ", WEXITSTATUS(status) );*/
/*Fork second subprocess */
pid_two = fork();
if( 0 == pid_two ) /*second child process block */
{
/* redirect stdin to pipe's read end for sub process two */
dup2(pipe_fd[0],0);
// close(0); /* close normal stdin */
// dup(pipe_fd[0]); /* make stdib same as pfds[0] */
/*close pipe write end */
close(pipe_fd[1]);
/* Second sub process */
/*printf("Second sub process is %d \n",getpid()); */
execvp(cmd_two_tokens[0] , cmd_two_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
}
else /*main process block */
{
/* printf(" Main process is %d \n",getpid()); */
status=-1; /*reset status */
/*Waiting for the second sub process to finish in No hang fashion */
waitpid ( -1 , &status ,WNOHANG);
/*printf("Exit status of second child is %d \n ", WEXITSTATUS(status) ); */
}
}
You have to close the pipe file descriptors in the main process, after the second is forked. Until you have closed them, the child process (wc) will wait for input on the pipe which the main process still has open. You must be very careful to close all the unneeded ends of the pipe.
Your code does not do what you describe you want to do:
You create a pipe, fork a new process, redirect it's stdout to the pipe and make it execute some program (so far so good), then in the parent process you wait for your child to finish and only then fork second process, redirect it's stdin to the pipe other end and make it execute another program.
This is not what "ls | wc" does - in the shell they are running concurrently. Remove the first wait().
pid_one = fork() ;
if( 0 == pid_one ) /*child process block */
You're not checking fork(2) for an error return, which is a very real possibility. (The user could be bumping up against their RLIMIT_NPROC limit, kernel.threads-max, run out of memory for holding task structures, etc.)
More idiomatic use of fork(2) looks like this:
if(-1 == (pid = fork()) {
perror("fork");
exit(1); /* or return -1 or similar */
} else if (0 == pid) {
/* executing as child */
} else {
/* parent, pid is child */
}
execvp(cmd_two_tokens[0] , cmd_two_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
Note that there are many reasons why execvp(3) can fail; simply printing "Unknown Command" may leave your users very confused in the future. It'd be better to call perror("execvp"); and give your users a chance to discover the real reason why their execvp(3) call failed.
waitpid ( -1 , &status ,WNOHANG);
Use of WNOHANG here might be dangerous; if the system is running "just right", your parent might get to this code before the child has even had a chance to begin executing. Because you've asked for it to return immediately if no child has exited, the child will probably be turned into a zombie when it finally does exit -- your code doesn't take the opportunity to wait for the child again.
I'm not sure what the best solution is: if you use SA_NOCLDWAIT to sigaction(2) to avoid creating zombies completely, you won't have an opportunity to ever collect the child's exit status. Installing a SIGCHLD signal handler might interfere with the rest of the process; your clients might have reason to set it themselves. Using a blocking waitpid(2) might stall processing elsewhere. And using a non-blocking waitpid(2) means you still have to collect the child's status sometime, possibly through polling. (But you can't use -1 for the pid in that case, as you might accidentally reap another child process.)

fork(), pipe() and exec() process creation and communication

I have to write program that create process using pipe().
My first task is to write a parent process that generates four child processes using the fork() function.
Once the fork() is successful, replace the child process with another process rover1, rover2, rover3, and rover4, though all of them have the same code.
The function of the processes is as follows.
Each child process is initially given its own number. It receives a new number from the parent. Using the following formula it creates its own new number as follows and forwards it to the parent:
mynumber = (3 * mynumber + 4 * numberreceived)/7
This process continues until the parent sends the message that the system is stable. The parent also has its initial number. It receives numbers of all the children and computes its new number as follows:
mynumber = (3 * mynumber + numbers sent by all the children)/7
The parent will send this number to all its children. This process will continue until the parent finds that its number is not changing anymore. At that time it will tell the children the system has become stable.
This is what I did but my professor said I have to use exec() to execute the child and replace child process with another child process. I am not sure how to use exec(). Could you please help me with this.
I am attaching only first child generation.
// I included stdio.h, unistd.h stdlib.h and errno.h
int main(void)
{
// Values returned from the four fork() calls
pid_t rover1, rover2, rover3, rover4;
int parentnumber, mynumber1, mynumber2, mynumber3, mynumber4;
int childownnumber1 = 0, status = 1, childownnumber2 = 0,
childownnumber3 = 0, childownnumber4 = 0, numberreceived = 0;
printf("Enter parent number: ");
printf("%d", parentnumber);
printf("Enter each children number");
printf("%d %d %d %d", mynumber1, mynumber2, mynumber3, mynumber4);
// Create pipes for communication between child and parent
int p1[2], p2[2];
// Attempt to open pipe
if (pipe(p1) == -1) {
perror("pipe call error");
exit(1);
}
// Attempt to open pipe
if (pipe(p2) == -1) {
perror("pipe call error");
exit(1);
}
// Parent process generates 4 child processes
rover1 = fork();
// if fork() returns 0, we're in the child process;
// call exec() for each child to replace itself with another process
if (rover1 == 0) {
for(; numberreceived != 1; ) {
close(p1[1]); // Close write end of pipe
close(p2[0]); // Close read end of second pipe
// Read parent's number from pipe
read(p1[0], &numberreceived, sizeof(int));
if (numberreceived == 1) {
// System stable, end child process
close(p1[0]);
close(p2[1]);
_exit(0); // End child process
}
mynumber1 = (int)((3*mynumber1 + 4*numberreceived)/7.0);
printf("\nrover1 number: ");
printf("%i", mynumber1);
// Write to pipe
write(p2[1], &mynumber1, sizeof(int));
}
}
/* Error:
* If fork() returns a negative number, an error happened;
* output error message
*/
if (rover1 < 0) {
fprintf(stderr,
"can't fork, child process 1 not created, error %d\n",
errno);
exit(EXIT_FAILURE);
}
}
The exec family of functions is used to replace the current process with a new process. Note the use of the word replace. Once exec is called, the current process is gone and the new process starts. If you want to create a separate process, you must first fork, and then exec the new binary within the child process.
Using the exec functions is similar to executing a program from the command line. The program to execute as well as the arguments passed to the program are provided in the call to the exec function.
For example, the following execcommand* is the equivalent to the subsequent shell command:
execl("/bin/ls", "/bin/ls", "-r", "-t", "-l", (char *) 0);
/bin/ls -r -t -l
* Note that "arg0" is the command/file name to execute
Since this is homework, it is important to have a good understanding of this process. You could start by reading documentation on pipe, fork, and exec combined with a few tutorials to gain a better understanding each step.
The following links should help to get you started:
IBM developerWorks: Delve into UNIX process creation
YoLinux Tutorial: Fork, Exec and Process control
Pipe, Fork, Exec and Related Topics
If you are supposed to use exec, then you should split your program into two binaries.
Basically, the code that now gets executed by the child should be in the second binary and should be invoked with exec.
Before calling one of the exec family of functions, you'll also need to redirect the pipe descriptors to the new process' standard input/output using dup2. This way the code in the second binary that gets exec'd won't be aware of the pipe and will just read/write to the standard input/output.
It's also worth noting that some of the data you are using now in the child process is inherited from the parent through the fork. When using exec the child won't share the data nor the code of the parent, so maybe you can consider transmitting the needed data through the pipe as well.

C signal parent process from child

I'm trying to solve a problem I've got where a child process runs execvp() and needs to let the parent know if it returns. So, after the execvp() returns (because there's been an error), how can I tell the parent that this particular event has happened so it can handle it.
There's one method of writing a string of text through the pipe I'm using and then reading that from the parent.. but it seems a bit sloppy. Is there a better way?
Thanks!
Edit: Here is some code I'm trying where I can't seem to get the read to return.
int errorPipe[2];
signal( SIGPIPE, SIG_IGN );
int oldflags = fcntl (errorPipe[0], F_GETFD, 0);
oldflags |= FD_CLOEXEC;
fcntl (errorPipe[0], F_SETFD, oldflags);
oldflags = fcntl (errorPipe[1], F_GETFD, 0);
oldflags |= FD_CLOEXEC;
fcntl (errorPipe[1], F_SETFD, oldflags);
pipe( errorPipe );
// in the child..
char *error_message = "exec failed";
write( errorPipe[1], error_message, strlen(error_message)+1 );
exit(-1);
// in the parent
printf("read gives: %d\n", read(errorPipe[0], error_read, MAX_LINE_LENGTH) );
The easiest way is a pipe with the FD_CLOEXEC flag set, as then you can detect a successful exec as easily as a failure. In the event of a failure, I'd write whole the error message back to the parent over the pipe, but you could just write the status code or anything else that is meaningful. (Definitely write something though; nothing written has got to be a sign of a successful start of the other executable.)
[EDIT]: How to make use of this:
If the parent needs to wait until it knows whether the child successfully ran execve() (the unlying syscall) then it should do a blocking read() on the pipe. A zero result from that indicates success. (Make sure you've got SIGPIPE ignored.)
If the parent has some kind of event handling framework based on non-blocking IO and select() (or poll() or kqueue() or …) then wait for the pipe to become readable before trying to read the message (which will be zero-length if the child did the execve() correctly).
execvp() never returns, except when it fails to even start the executable at all. If it can start the executable, it will not return, no matter what the executable does (i.e. regardless to whether the executable succeeds at its task or not).
Your parent process will receive a SIGCHLD signal, for which you can install a signal handler.
Or you can wait(2) for the child process.
int child_pid = fork();
if (child_pid == 0) {
execvp("/path/to/executable", ...);
exit(123); /* this happens only if execvp() fails to invoke executable */
}
/* ... */
int status = 0;
int exit_pid = waitpid(-1, &status, WNOHANG);
if (exit_pid == child_pid && WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0) {
/* child process exited fine */
} else if (WEXITSTATUS(status) == 123)
/* execvp() itself failed */
} else {
/* executed child process failed */
}
}
Cache the pid for the (child) process for which you want to examine the status in the parent.
Add a handler for SIGCHLD in the parent. In the child call exit with some status value of your choosing to denote that execvp failed. On receiving the signal in the parent you now have 2 options
a) Call waitpid with a pid of -1 (i.e. wait for any child), examine the return value, if that matches your cached pid, examine the status using macros like WEXITSTATUS.
b) Call waitpid with your cached pid , then on return examine the exit status.
To make this robust you should call WIFEXITED(status) before examining the exit status via WEXITSTATUS. WIFEXITED returns true if the child terminated normally i.e. by calling exit or _exit and not as a result of seg fault, un handled signal etc.
Also see man wait(2).

Resources