I have a question about the use of execvp(), for the following function, if I am in child process and the execvp() function is executed successfully (according to the man page, it will not return), if the script outside of else {} will keep working, which means if the execCmd() function will return any value?
int execCmd(char* args[10]) {
pid_t pid = fork();
if (pid < 0) {
exit(1);
} else if (pid > 0) { // parent process
/* do something */
} else {
if (execvp(*args, args) < 0) {
printf("Execution Failed!");
exit(1);
}
}
return 0;
}
Thanks in advance!
If execvp is successful, the process starts executing the specified program.
Parent Process Child Process
------------------- -------------------
fork()
pid_t pid = ...; pid_t pid = ...;
pid < 0 pid < 0
pid > 0 pid > 0
/* do something */ execvp(*args, args)
return 0; [main of new program]
Your program could have been written
int execCmd(char** args) {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
execvp(*args, args);
perror("execvp");
_exit(1);
}
/* ... Do something in parent ... */
return 0;
}
Also, you probably want to wait for the child to finish, return the pid or have the child auto-reap (by making SIGCHILD ignored).
in general, the code should not be executing misc statements;
The code should only need to test the results of the call to fork() once.
Notice, there is no need to wrap the call to execvp() in an if() code block
The parent process should wait for the child process to complete before exiting.
When an error occurs, should output an error message to stderr via a call to fprintf( stderr, "...\n" ) However, when the error is from a system function, the reason the system thinks the error occurred should also be output to stderr. A simple way to accomplish this is by calling perror()
for ease of readability and understanding: separate code blocks ( for if else while do...while switch case default ) via a single blank line.
the preferred code logic for a call to fork() is:
int execCmd(char* args[10])
{
pid_t pid;
switch( pid = fork() )
{
case -1: // error
perror( "fork failed" );
exit(1);
break;
case 0: // child
execvp(*args, args);
perror( "execvp Failed!" );
exit(1);
break;
default: // parent
/* do something */
waitpid( pid, NULL );
break;
}
return 0;
}
Related
For some unknown reason, when I'm executing piped commands in my shell program, they're only outputting once I exit the program, anyone see why?
Code:
int execCmdsPiped(char **cmds, char **pipedCmds){
// 0 is read end, 1 is write end
int pipefd[2];
pid_t pid1, pid2;
if (pipe(pipefd) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
pid1 = fork();
if (pid1 < 0) {
fprintf(stderr, "Fork Failure");
}
if (pid1 == 0) {
// Child 1 executing..
// It only needs to write at the write end
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
if (execvp(pipedCmds[0], pipedCmds) < 0) {
printf("\nCouldn't execute command 1: %s\n", *pipedCmds);
exit(0);
}
} else {
// Parent executing
pid2 = fork();
if (pid2 < 0) {
fprintf(stderr, "Fork Failure");
exit(0);
}
// Child 2 executing..
// It only needs to read at the read end
if (pid2 == 0) {
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
if (execvp(cmds[0], cmds) < 0) {
//printf("\nCouldn't execute command 2...");
printf("\nCouldn't execute command 2: %s\n", *cmds);
exit(0);
}
} else {
// parent executing, waiting for two children
wait(NULL);
}
}
}
Output:
In this example of the output, I have used "ls | sort -r" as the example, another important note is that my program is designed to only handle one pipe, I'm not supporting multi-piped commands. But with all that in mind, where am I going wrong, and what should I do to fix it so that it's outputting within the shell, not outside it. Many thanks in advance for any and all advice and help given.
The reason would be your parent process file descriptors are not closed yet. When you wait for the second command to terminate, it hangs because the writing end is not closed so it wait until either the writing end is closed, or new data is available to read.
Try closing both pipefd[0] and pipefd[1] before waiting for process to terminate.
Also note that wait(NULL); will immediately return when one process has terminated, you would need a second one as to not generate zombies if your process still runs after that.
"ulimit -c unlimited" has been done. Here is the code:
main()
{
do
{
pid_t pid = fork();
int stat_loc;
if(pid < 0)
exit(1);
else if(pid > 0)
{
waitpid(pid, &stat_loc, 0);
sleep(5);
}
else
break;
}
while(1);
assert(0);
}
If I replace sleep(5) with assert(0) the parent process dumps core.
Calling assert(0) on a debug build of your application should cause an abort:
If the argument expression of this macro with functional form compares equal to zero (i.e., the expression is false), a message is written to the standard error device and abort is called, terminating the program execution.
What are you actually looking to do here? It looks like there may be a problem with your forking logic. Typically you test to see if pid == 0 to see if you're in the child process and pid > 0 to see if you're in the parent process, like this:
pid_t pid = fork();
if (pid == 0) {
// child process because return value zero
printf("Hello from Child!\n");
} else if (pid > 0) {
// parent process because return value non-zero.
printf("Hello from Parent!\n");
} else {
printf("Error occurred.\n");
}
In your question you're checking for > 0 and < 0.
Edit: Added error checking branch.
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.
I'm currently creating my own command line shell, and I'm having problems when trying to take in pipes. My program starts with the parent process. It checks to see if the user puts in exit or history. If so it uses those commands, but this is not important. If the user puts in anything other than exit or history, then it creates a child who executes the current task.
However, if the user puts in a command that has a single pipe, then we start at the parent and it creates a child process, call this child, child 1. child 1 see's that there is a pipe and uses fork to create another child, call this child 2. Child 1 creates another child, call it child 3 (Note: child 2 and 3 use shared memory). Now, child 2 executes the first command, and child 3 executes the command using child 2's output. But I'm not getting any output for some reason.
I'm not sure if this is the most efficient way of executing my task, but this is what my professor said to do.
If you want to see all of my code here it is: http://pastebin.com/YNTVf3XP
Otherwise here is my code starting at child 1:
//Otherwise if we have a single pipe, then do
else if (numPipes == 1) {
char *command1[CMD_MAX]; //string holding the first command
char *command2[CMD_MAX]; //string holding the second command
int fds[2]; //create file descriptors for the parent and child
pid_t new_pid; //create new pid_t obj
onePipeSplit(tokens, command1, command2, numTokens); //Getting each command for pipe
if (pipe(fds) < 0) { //use the pipe command. If < 0
perror("Pipe failure."); //we have an error, so exit
exit(EXIT_FAILURE);
}
//Creating child 2
new_pid = fork();
//if pid < 0 then we have an error. Exit.
if (new_pid < 0) {
perror("Fork failure.");
exit(EXIT_FAILURE);
}
//Else we have the child (2) process
else if (new_pid == 0) {
close(fds[0]); //Close read
//sending stdin to the shared file descriptor
if (dup2(fds[1], STDOUT_FILENO)<0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
execvp(command1[0], command1); //Execute the next command
perror("Exec failure");
exit(EXIT_FAILURE);
}
//Else if we have the parent process
else {
pid_t child = fork(); //Creating child 3
if (new_pid < 0) { //if pid < 0, error, exit
perror("Fork failure.");
exit(EXIT_FAILURE);
}
//else if pid > 0 we have the parent wait until children execute
else if (new_pid > 0) {
wait(NULL);
}
//else we have the child (3)
else {
close(fds[1]); //Close write
//Sending stdout to the shared file descriptor
if (dup2(fds[0], STDIN_FILENO) < 0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
execvp(command2[0], command2); //Execute the command
perror("Exec failure");
exit(EXIT_FAILURE);
}
}
}
Here is an image that my professor gave me to show how it should work.
The problem is here:
pid_t child = fork(); //Creating child 3
if (new_pid < 0) {
... you keep checking `new_pid` here on down,
... but you should be checking `child` here on down...
Also in onePipeSplit you need to put a NULL at the end of both command lists because execvp needs that. After the first loop add:
command1[i] = NULL;
and after the second:
command2[i] = NULL;
OK, a few more fixes:
after each dup2() you need to close the original fd. One example:
if (dup2(fds[1], STDOUT_FILENO)<0) {
perror("Can't dup");
exit(EXIT_FAILURE);
}
close(fds[1]); /* ADD ME */
and in the parent process:
//else if pid > 0 we have the parent wait until children execute
else if (child > 0) {
close(fds[0]); /* we don't use */
close(fds[1]); /* the pipe */
wait(NULL);
exit(0); /* when 2 & 3 are done, we are too */
}
I do a double fork (fork, then the child forks again, I wait for the child, the grandchild is handled by init) in a process and after the child has closed I try to read from a socket that I had open in the parent previous to the fork. The read fails every time I run the program.
The message is being sent using sendto() which returns an error code of ENOENT.
Should this be working or am I [10]?
Here is the code in the function that forks:
uint8_t
upgrade(
char *server,
char *file)
{
pid_t pid1, pid2;
int status;
if ((pid1 = fork()) < 0)
{
/* Fork error */
log("FAILED: First fork() failed");
}
else if (pid1 == 0)
{
/* First child */
if ((pid2 = fork()) < 0)
{
/* Fork error */
log("FAILED: Second fork() failed");
exit(0);
}
else if (pid2 == 0)
{
/*
execl("/usr/sbin/system_upgrade",
"system_upgrade", NULL);
*/
exit(0);
}
else
{
/* Second parent ie. First child
* Note: Exit cleanly so that second child
* gets reparented to init, and we avoid a zombie process */
exit(0);
}
}
else
{
/* First parent, wait for first child to exit */
if (waitpid (pid1, &status, 0) != pid1)
{
log("FAILED: waitpid() failed");
}
} /* FORK */
return OK;
}
edit: removed extra bracket, fixed indentation, marked it as code again