Reputation: 69
I'm trying to redirect child process's input and output stream, without redirect parent process input and output stream.
My idea was to check whether or not there is an input\output in the command line, if so to redirect to it, then fork and wait for child to complete it's process if necessary, and eventually redirect back to stdin
and stdout
. The problem is that this code somehow doesn't redirect back to stdin
and stdout
and the parent process stays in the previous streams.
Here is my code:
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;
void execute(cmdLine *pCmdLine){
FILE * input = NULL;
FILE * output = NULL;
if(pCmdLine->inputRedirect != NULL){
close(fileno(stdin));
input = fopen(pCmdLine->inputRedirect, "r+"); //open for child
}
if(pCmdLine->outputRedirect != NULL){
close(fileno(stdout));
output = fopen(pCmdLine->outputRedirect, "ab+"); //open for child
}
pid = fork();
if(pCmdLine->blocking == 1) {
waitpid(pid, NULL, 0); //wait for chile to finish
if (input){ //redirect to stdin
close(input);
fopen(stdin, "r+");
fflush(stdin);
}
if (output){ //redirect to stdout
close(output);
fopen(stdout, "ab+");
fflush(stdout);
}
}
if(pid == 0){
execvp(pCmdLine-> arguments[0],pCmdLine->arguments); //exec child
perror("execution went wrong!");
exit(-1);
}
}
How should I do in correctly and elegant?
Notes: without using dup2 and pipe, or any other libraries rather than those: unistd.h,stdio.h,stdlib.h,string.h,sys/wait.h
Upvotes: 1
Views: 637
Reputation: 74118
Redirecting shall be done by closing and reopening standard input and standard output respectively. And it shall be done in the child process only.
This may be done by doing it in the child branch
pid_t pid = fork();
if (pid == -1) {
// error handling
perror("fork");
} else if (pid == 0) {
// Now we're in the child process
if (pCmdLine->inputRedirect != NULL) {
fclose(stdin);
input = fopen(pCmdLine->inputRedirect, "r+"); // open for child
}
if (pCmdLine->outputRedirect != NULL) {
fclose(stdout);
output = fopen(pCmdLine->outputRedirect, "ab+"); // open for child
}
execvp(pCmdLine->arguments[0], pCmdLine->arguments); // exec child
perror("execution went wrong!");
exit(-1);
} else {
// Now we're in the parent process
waitpid(pid, NULL, 0);
}
Upvotes: 1