Reputation: 85
I'm trying to write a small shell program and I want it to remain active after invoking another program (via execvp()
). I want the fork
system call to 'duplicate' the process, creating an almost identical copy (child) of the issuing (parent) process. So when the parent terminates because of the excevp()
call the children will be still alive.
In the code I attached bellow, I read a user input (program and arguments to execute) and then I expect that the parent fork will execute the program and the child fork will wait for the next input by the user, but after the first time I insert input (the program to execute and its arguments), the program gets stuck in a infinite loop. When the child fork takes control, it executes the previous program and doesn't wait for new input (seems like after the first fgets()
it doesn't wait for user input anymore).
Here's the problematic part of the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "LineParser.h"
#include <limits.h>
#include <unistd.h>
char buf[PATH_MAX];
char buf_user[2048];
int pid;
void execute(cmdLine* pCmdLine) {
int pid = fork();
if(pid != 0) {
printf("I'm the parent.\n");
if(execvp(pCmdLine->arguments[0], pCmdLine->arguments) == -1) {
perror("execute failed");
_exit(1);
}
} else {
freeCmdLines(pCmdLine);
}
}
int main(int argc, char *argv[])
{
while(1) {
getcwd(buf, PATH_MAX);
printf("%s> ", buf);
fgets(buf_user, 2048, stdin);
fflush(stdin);
if(strcmp(buf_user, "quit\n") == 0) {
exit(0);
}
cmdLine* parsedCmd = parseCmdLines(buf_user);
execute(parsedCmd);
}
return 0;
}
cmdLine
structure:
#define MAX_ARGUMENTS 256
typedef struct cmdLine
{
char *const arguments[MAX_ARGUMENTS]; /* command line arguments (arg 0 is the command) */
int argCount; /* number of arguments */
char const *inputRedirect; /* input redirection path. NULL if no input redirection */
char const *outputRedirect; /* output redirection path. NULL if no output redirection */
char blocking; /* boolean indicating blocking/non-blocking */
int idx; /* index of current command in the chain of cmdLines (0 for the first) */
struct cmdLine *next; /* next cmdLine in chain */
} cmdLine;
/* Parses a given string to arguments and other indicators */
/* Returns NULL when there's nothing to parse */
/* When successful, returns a pointer to cmdLine (in case of a pipe, this will be the head of a linked list) */
cmdLine *parseCmdLines(const char *strLine); /* Parse string line */
/* Releases all allocated memory for the chain (linked list) */
void freeCmdLines(cmdLine *pCmdLine); /* Free parsed line */
/* Replaces arguments[num] with newString */
/* Returns 0 if num is out-of-range, otherwise - returns 1 */
int replaceCmdArg(cmdLine *pCmdLine, int num, const char *newString);
Upvotes: 1
Views: 1455
Reputation: 46
You should not execvp in the parent, but in the child.
Your terminal waits for the parent to finish. Finishing the parent without waiting for it's child to end results in a zombie process.
Modifying your code in order to exec the command in the child and waiting for it to finish in the parent solved your issue when I tested it.
I suggest you read the man 3 wait !
Upvotes: 1