C pipe: Bad file descriptor - c

I have the simple producer consumer program in C try to solve it with fork
I get error exactly when producer tries to write on pipe:
I have wrote another program with the same logic but this one does not give me any clue to know why?
Producer failed to write item on pipe: Bad file descriptor
Anyone have idea why I get this error?
Thanks
#define READ 0
#define WRITE 1
int mutex = 1, full = 0, empty = BUFFER_SIZE, x = 0;
void consumer();
void producer();
int wait_(int);
int signal_(int);
int pipefd[2];
int main() {
printf("Starting producer-consumer problem!\n");
//We intend to run the producer in parent process and the consumer in the child process
if (pipe(pipefd) == -1) { /* An error has occurred. */
fprintf(stderr, "%s", "The call to pipe() has failed.\n");
exit(EXIT_FAILURE);
}
for (int j = 0; j < sizeof(pipefd); j++) {
if (pipe(&pipefd[j]) < 0) { //Initialize each pipe appropriately
perror("Error in making pipe...");
}
}
pid_t pid = fork();
if (pid < 0) {
perror("**********Error in creating fork()!**************\n");
exit(STDERR_FILENO);
} else if (pid == 0) {
consumer();//We intend to run the consumer in child
} else {
producer();//We intend to run the producer in parent
}
return 0;
}
int wait_(int s) {
return (--s);
}
int signal_(int s) {
return (++s);
}
void producer() {
printf("Starting Producer\n");
//while (1) {
//sleep(1);
if (close(pipefd[READ]) != 0) {
perror("Error in closing reading pipe");
}
if (write(pipefd[WRITE], &full, 1) < 0) {
perror("Producer failed to write item on pipe");
}
if ((mutex == 1) && (empty != 0)) {
mutex = wait_(mutex);
full = signal_(full);
empty = wait_(empty);
x++;
printf("Producer produces the item %d\n", x);
mutex = signal_(mutex);
}
if (close(pipefd[WRITE]) != 0) {
perror("Error in closing writing pipe");
}
//}
}
void consumer() {
printf("Starting Consumer\n");
//while (1) {
//sleep(1);
int status = 0;
wait(&status); /* wait for all children to return back the result */
if (close(pipefd[WRITE]) != 0) {
perror("Error in closing reading pipe");
}
if (read(pipefd[READ], &full, 1) > 0) {
printf("Consumer\t%d\n", full);
}
if ((mutex == 1) && (full != 0)) {
mutex = wait_(mutex);
full = wait_(full);
empty = signal_(empty);
printf("Consumer consumes item %d\n", x);
x--;
mutex = signal_(mutex);
}
if (close(pipefd[READ]) != 0) {
perror("Error in closing reading pipe");
}
//}
}

The sizeof operator returns the size in bytes. So on a typical system where an int is four bytes, sizeof(pipefd) would result in the value 8. Which is not the correct number of elements for your loop.
Also, pipe(&pipefd[j]) is not correct either. The two pipes in pipefd are already initialized "appropriately". There's no need for any more initialization. Especially since in both this and the previous case you will have undefined behavior.

Related

Creating a new child process when old one is terminated in C

I've included code that creates a series of child processes to divide the work for a task. There's a random chance for it to terminate (handled by the word_count function from which it calls abort()) and on this event, it should create a new child process to replace it. However, the program is being blocked on the read. I know this code is messy, but I want understand the problem before cleaning it up.
int pipes[nChildProc][2]; //pipe fd[0] is read end, fd[1] is write end
long child_f_size = fsize / nChildProc;
pid_t pids[nChildProc];
//start dividing the work among child processes
for(int i = 0; i < nChildProc; ++i) {
//srand(time(NULL));
//int crash = ((rand() / RAND_MAX + 1.0) < crashRate) ? 1 : 0;
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
//wait for a children to finish
int ret, status, i = 0;
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
if(ret == -1) {
continue;
}
if(ret != 0) {// didn't exit normally
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
i = (i + 1) % nChildProc;//loop back to detect more processes that were terminated
}
long bytes;
count_t temp;
temp.linecount = 0;
temp.wordcount = 0;
temp.charcount = 0;
//add up all the values from children to count
printf("time to read.\n");
for(unsigned int j = 0; j < nChildProc; ++j) {
if((bytes = read(pipes[j][0], &temp, sizeof(temp))) < 0) {//blocked here
printf("Failed to read from pipe {%d}.\n", j);
exit(1);
}
if(bytes != 0) {
count.linecount += temp.linecount;
count.wordcount += temp.wordcount;
count.charcount += temp.charcount;
}
close(pipes[j][1]);
close(pipes[j][0]);
}
A couple of issues jump out:
if(ret != 0) {// didn't exit normally you've confused ret (which is the pid) for status (which is the exit code of the child)
You can't call wait on a process twice, since calling wait allows the system to release the resources associated with the process. You have several options on how to rewrite this code:
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
One easy way is to use wait then lookup in the array which index it belongs to.
while((pid = wait(&status)) {
if (pid == -1) { // no children to wait on
break;
}
for(int i = 0; i < nChildProc; ++i) {
if (pid == pids[i]) break;
}
if (i >= nChildProc) {
unexpected_pid_do_something_smart();
}
// Leave the rest of the loop the same
Note: I didn't compile or test the above code.

Creating Shell in C - Piping and External Commands

I am trying to create a small shell using C. At the moment I am trying to figure out piping and external commands. I got stuck in them both even after looking at various youtube videos.
I referred to MAN and even Advanced Linux Programming
What can I change to improve and make the implementation work?
This a part of the checking of commands, args := tokenisation by whitespace, commLHS := will be used to store args before | and commRHS will be used to store args after | and indexT refers to the number of arguments inputted
else if((check4pipe(args, commLHS, commRHS, indexT) != 0))
{
return runPipeComm(commLHS, commRHS);
//fprintf(stderr, "%s: command not found\n", args[0]);
}
This will execute External Commands
void externalCommands(char **args)
{
// fork-plus-exec pattern
// https://www.percona.com/community-blog/2021/01/04/fork-exec-wait-and-exit/
/*
First we Fork
Then we Exec
Then we Wait
Then we Exit
*/
int status;
pid_t pip = fork();
if (pip == -1)
{
perror("Error - fork()");
}
else if (pip == 0)
{
//If PID is the child process
//Launches the process.
if (execvp(args[0], args) < 0)
{
perror("Error - execvp()");
}
}
else
{ //If PID is the parent process.
//Waits for the child process and returns exit code if waitpid() is successful.
if(waitpid(pip, &status, WUNTRACED) == -1)
{
perror("Error occured during waitpi");
}
else
{
//set_exitcode(status); //Sets the exitcode environment variable.
}
}
}
This is to check for | in args inputted by user after tokenisation.
int check4pipe(char **args, char **pipeLHS, char **pipeRHS, int indexT)
{
bool foundPipe = false;
for(int i = 0; i < indexT; i++)
{
if(strcmp(args[i], "|") == 0)
{
foundPipe = true;
memcpy(pipeLHS, args, (i+1) * sizeof(char*));
pipeLHS[i] = NULL;
memcpy(pipeLHS, args+(i+1), ((indexT-i)+1) * sizeof(char*));
pipeRHS[i]= NULL;
}
else
{
continue;
}
}
if(foundPipe == true)
{
return 1;
}
else
{
return 0;
}
}
This will run the pipe commands
int runPipeComm(char **commLHS, char **commRHS)
{
int userPipe[2];
pid_t pip1; // Pipe ID 1
pid_t pip2; // Pipe ID 2
if(pipe(userPipe) < 0)
{
perror("Error Occurred while piping: ");
}
// Start Process
pip1 = fork();
if(pip1 == -1)
{
perror("Error Occurred while forking: ");
}
else if(pip1 == 0)
{
dup2(userPipe[1], STDOUT_FILENO);
close(userPipe[1]);
//run
exit(0);
}
else
{
pip2 = fork();
if(pip2 == -1)
{
perror("Error Occurred while forking: ");
}
else if(pip2 == 0)
{
dup2(userPipe[0], STDOUT_FILENO);
close(userPipe[1]);
//run
exit(0);
}
else
{
close(userPipe[0]);
close(userPipe[1]);
wait(NULL);
wait(NULL);
}
}
return 1;
}
You forgot to change some things when copying snippets within your program.
wrong:
memcpy(pipeLHS, args+(i+1), ((indexT-i)+1) * sizeof(char*));
pipeRHS[i]= NULL;
right:
memcpy(pipeRHS, args+(i+1), (indexT-(i+1)) * sizeof (char*));
pipeRHS[indexT-(i+1)] = NULL;
wrong:
dup2(userPipe[0], STDOUT_FILENO);
close(userPipe[1]);
right:
dup2(userPipe[0], STDIN_FILENO);
close(userPipe[0]);
After the first //run line, add the missing
execvp(*commLHS, commLHS);
perror("Error - execvp()");
After the second //run line, add the missing
execvp(*commRHS, commRHS);
perror("Error - execvp()");
Finally, the write end of the pipe must be closed in the parent process, so move the close() there:
close(userPipe[1]);
pip2 = fork();

Creating a shell in C that handles redirection and pipes

The following function successfully executes any command that doesn't contain pipes, so don't worry about the weird functions. These work. The problem I am having is that whenever I execute any command like the following:
cat file.txt | grep string
the command is successfully executed, but it remains idle, so somehow it gets stuck and no other command can execute. why is this happening?. I think it has something to do with the way I use pipe, dup and fork, so try to approach the problem from these functions. I know you may be arguing that this code doesn't work for other commands with pipes, but I just want to get this particular example to work and to do so I just redirect STDIN to the open file in the first iteration.
int myshell_execute(struct processNode* list, int a)
{
struct processNode* myList = list; // next node to be handled
int pipefd[2];
int in=0;
if (pipe(pipefd) == -1) {
perror("pipe");
myshell_exit(-1);
}
while(myList != NULL)
{
char* program = myList->program; // Get the program to be executed
char ** program_args = myList->program_arguments; // get the programs and arguments to be executed
char ** redirection_string = myList->redirection; //get the part of the command that contains redirection
int *status;
int* stdout;
int stdout_num = 1;
stdout = &stdout_num;
int fileDescriptor;
pid_t pid;
if(strcmp(program,"cd") == 0)
{
return myshell_cd(program_args);
}
else if (strcmp(program,"exit") == 0)
{
return myshell_exit(0);
}
pid = fork();
if(pid == 0)
{
if(in == 1)
{
close(pipefd[1]);
dup2(pipefd[0],0);
close(pipefd[0]);
}
if(sizeOfLine(redirection_string) != 0)
{
redirectionHandler(redirection_string,stdout); // This works. This just handles redirection properly
}
if(*stdout == 1 && myList->next !=NULL)
{
close(pipefd[0]);
dup2(pipefd[1],STDOUT_FILENO); // with this
close(pipefd[1]);
}
if(execvp(program,program_args) !=-1)
{
perror("myshell:");
myshell_exit(-1);
}
else{
myshell_exit(0);
}
}
else if (pid <0)
{
perror("myshell: ");
myshell_exit(-1);
}
else
{
wait(status);
}
in = 1;
myList = myList->next;
}
}
new solution:
int helper_execute(int in, int out, char* program, char ** program_args, char *redirection)
{
pid_t pid;
if ((pid = fork ()) == 0)
{
if (in != 0)
{
dup2 (in, 0);
close (in);
}
if (out != 1)
{
dup2 (out, 1);
close (out);
}
redirectionHandler(redirection);
return execvp (program, program_args);
}
return pid;
}
int myshell_execute(struct processNode* list, int a)
{
int i;
pid_t pid;
int in, fd [2];
struct processNode*new_list = list;
char ** newProgram = new_list->program_arguments;
char ** redirection = new_list->redirection;
char * program = new_list->program;
/* The first process should get its input from the original file descriptor 0. */
in = 0;
/* Note the loop bound, we spawn here all, but the last stage of the pipeline. */
while(new_list->next != NULL)
{
pipe (fd);
/* f [1] is the write end of the pipe, we carry `in` from the prev iteration. */
helper_execute (in, fd [1],program,newProgram,redirection);
/* No need for the write end of the pipe, the child will write here. */
close (fd [1]);
/* Keep the read end of the pipe, the next child will read from there. */
in = fd [0];
new_list = new_list->next;
}
/* Last stage of the pipeline - set stdin be the read end of the previous pipe
and output to the original file descriptor 1. */
if (in != 0)
dup2 (in, 0);
/* Execute the last stage with the current process. */
char* lastProgram = new_list->program;
char ** lastRedirection = new_list->redirection;
char * lastPrArguments = new_list->program_arguments;
redirectionHandler(redirection);
return execvp (lastProgram, lastPrArguments);
}
int main() {
int i=0;
char **input;
struct processNode* list;
int tracker = 0;
while ((input = getline()) != EOF) {
list = create_list(input);
myshell_execute(list,0);
}
return 0;
}
The only problem with this solution is that as soon as one command is executed, the main immediately detects the end of the file, so it exits the shell.
This is because
your parent process also holds the pipe open,
just after forking you call wait. If your first process (cat) fills its output pipe and there is not any process yet available to consume the read end of the pipe then the process stalls forever.
It would look like this:
#define MAX_PIPE_LEN 256
int myshell_execute(struct processNode* list, int a)
{
/* fd0 are the input and output descriptor for this command. fd1
are the input and output descriptor for the next command in the
pipeline. */
int fd0[2] = { STDIN_FILENO, STDOUT_FILENO },
fd1[2] = { -1, -1 };
pid_t pids[MAX_PIPE_LEN] = { 0 };
int pipe_len;
struct processNode* myList; // next node to be handled
int status;
int failed = 0;
for (pipe_len = 0, myList = list;
pipe_len < MAX_PIPE_LEN && myList != NULL;
pipe_len++, myList = myList->next) {
char* program = myList->program; // Get the program to be executed
char ** program_args = myList->program_arguments; // get the programs and arguments to be executed
char ** redirection_string = myList->redirection; //get the part of the command that contains redirection
if(strcmp(program,"cd") == 0) {
return myshell_cd(program_args);
}
else if (strcmp(program,"exit") == 0) {
return myshell_exit(0);
}
if (myList->next != NULL) {
/* The output of this command is piped into the next one */
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe failed");
failed = 1;
break;
}
fd1[0] = pipefd[0];
fd1[1] = fd0[1];
fd0[1] = pipefd[1];
}
pids[pipe_len] = fork();
if (pids[pipe_len] < 0) {
perror("error: fork failed");
failed = 1;
break;
}
if (pids[pipe_len] == 0) {
if (fd0[0] != STDIN_FILENO) {
if (dup2(fd0[0], STDIN_FILENO) == -1) {
perror("error: dup2 input failed");
abort();
}
close(fd0[0]);
}
if (fd0[1] != STDOUT_FILENO) {
if (dup2(fd0[1], STDOUT_FILENO) == -1) {
perror("error: dup2 outut failed");
abort();
}
close(fd0[1]);
}
if (fd1[0] >= 0) {
close(fd1[0]);
}
if (fd1[1] >= 0) {
close(fd1[1]);
}
if(sizeOfLine(redirection_string) != 0) {
redirectionHandler(redirection_string,stdout); // This works. This just handles redirection properly
}
execvp(program, program_args);
perror("error: execvp failed");
abort();
}
if (fd0[0] != STDIN_FILENO) {
close(fd0[0]);
}
if (fd1[1] != STDOUT_FILENO) {
close(fd0[1]);
}
fd0[0] = fd1[0];
fd0[1] = fd1[1];
fd1[0] = fd1[1] = -1;
}
if (myList->next) {
fprintf(stderr, "ERROR: MAX_PIPE_LEN (%d) is too small\n",
MAX_PIPE_LEN);
}
if (fd0[0] >= 0 && fd0[0] != STDIN_FILENO) {
close(fd0[0]);
}
if (fd0[1] >= 0 && fd0[1] != STDOUT_FILENO) {
close(fd0[1]);
}
if (fd1[0] >= 0) {
close(fd1[0]);
}
if (fd1[1] >= 0 && fd1[1] != STDOUT_FILENO) {
close(fd1[1]);
}
/* Now wait for the commands to finish */
int i;
for (i = 0; i < pipe_len; i++) {
if (waitpid(pids[pipe_len - 1], &status, 0) == -1) {
perror("error: waitpid failed");
failed = 1;
}
}
if (failed)
status = -1;
myshell_exit(status);
}

C - dup2() not executing

This is my first question so I apologize if I'm omitting anything important. So I've been working on an assignment that handles piping via forking. My code is pretty messy, littered with printf statements so I see what's going on.
I've looked around online and I think I get the idea of how to handle piping, but the problem I'm having is that my code skips dup2() on any file descriptor except inFD and outFD.
Here's the code for my function. Also, from what I understand, my teacher made a macro called CHK which checks for errors. If there is an error (such as dup2 returning -1), it'll terminate with a print to stderr.
My includes, global variables and myhandler() for signal
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <math.h>
#include <signal.h>
// Function calls
void parse(char *w, char **ptrArray, char *inArray, char *outArray, int *pipeArray);
int flagHandler(char **ptrArray, char *inArray, char *outArray);
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray);
// Global Variables
const int STORAGE = 254;
const int MAXITEM = 100;
int inFD; // file descriptor for <
int outFD; // file descriptor for >
int complete = 0; // for sighandler
int readDes = 0;
int writeDes = 1;
int numPipes = 0;
int status;
int forCounter = 0;
int fildes[4];
int pipeIndex = 0;
// MetaChar flags
int lessthanSign = 0; // < flag
int greaterthanSign = 0; // > flag
int firstChildFlag = 0;
int lastChildFlag = 0;
void myhandler(int signum)
{
complete = 1;
}
My main function
int main()
{
char s[STORAGE]; // array of words
char *newargv[MAXITEM];
char inArray[STORAGE]; // for <
char outArray[STORAGE]; // for >
int firstCheck;
int pidBackground; // holds value from fork(), used for background calls
struct stat st; // for stat(), checks if file exists
// dynamic array based on numPipes
// first child doesn't use this array, as it uses newargv[0] and newargv
// only the middle children and last child use this array, hence 10
int *pipeArray = malloc(10 * sizeof(int));
int numLoops = 0;
int i = 0;
signal(SIGTERM, myhandler);
for(;;)
{
// Reset flags here
lessthanSign = 0;
greaterthanSign = 0;
pipeSign = 0;
firstChildFlag = 0;
lastChildFlag = 0;
pipeIndex = 0;
parse(s, newargv, inArray, outArray, pipeArray);
pipeHandler(newargv, inArray, outArray, pipeArray);
wait(NULL);
fflush(NULL);
} // end for
printf("Entering killpg; numLoops = %d\n", numLoops);
killpg(getpid(), SIGTERM);
printf("p2 terminated.\n");
exit(0);
} // end main
Main calls parse which fills in newargv[]. It also fills in inArray[] and outArray[] with the string immediately after a < and > respectively. When detecting a pipe sign, it puts a null on newargv[], as well as putting a value in pipeArray[] for indexing the executable's name in newargv. I omitted the parse() and flagHandler() calls to keep it minimal.
My parseHandler() function
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray)
{
pid_t firstChild;
pid_t firstChildBackground;
pid_t middleChild;
pid_t lastChild;
pid_t lastChildBackground;
int i = 0; // plain integer for for loops
printf("Initializing pipes\n");
//pipe(fildes);
//pipe(fildes + 2);
for (i = 0; i < (2*numPipes); i+=2)
{
printf("pipe initializing; i is %d\n", i);
if (pipe(fildes + i) < 0)
{
perror("pipe initialization failed");
exit(EXIT_FAILURE);
}
}
fflush(stdout);
if ((firstChild = fork()) < 0)
{
perror("First child's fork failed!");
exit(EXIT_FAILURE);
}
printf("firstChild pid = %d\n", getpid());
if (firstChild == 0)
{
if (firstChildFlag == 1)
{
printf("inFD = open...\n");
inFD = open(inArray, O_RDONLY);
printf("Doing dup2 inFD\n");
if (dup2(inFD, STDIN_FILENO) < 0)
{
perror("First child's < dup2 failed");
exit(EXIT_FAILURE);
}
}
printf("doing dup2 fildes[writeDes]\n");
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("First child's dup2 failed");
exit(EXIT_FAILURE);
}
printf("*****doing dup2 fildes[writeDes] was a success!\n");
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (firstChildFlag == 1)
{
lessthanSign = 0;
firstChildFlag = 0;
if (close(inFD) < 0)
{
perror("close inFD failed");
exit(EXIT_FAILURE);
}
}
writeDes += 2;
printf("About to execvp first child\n");
if (execvp(ptrArray[0], ptrArray) < 0)
{
perror("execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((middleChild = fork() < 0))
{
perror("Middle child's fork failed");
exit(EXIT_FAILURE);
}
printf("middleChild pid = %d\n", getpid());
if (middleChild == 0)
{
if (dup2(fildes[readDes], STDIN_FILENO) < 0)
{
perror("Middle child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("Middle child's dup2 on writing failed");
exit(EXIT_FAILURE);
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
readDes += 2;
writeDes += 2;
if (execvp(ptrArray[pipeArray[0]], ptrArray + pipeArray[0]) < 0)
{
perror("Middle child's execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((lastChild = fork() < 0))
{
perror("Last child's fork failed");
exit(EXIT_FAILURE);
}
printf("lastChild pid = %d\n", getpid());
if (lastChild == 0)
{
if (dup2(fildes[readDes], STDOUT_FILENO) < 0)
{
perror("Last child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (lastChildFlag == 1)
{
outFD = open(outArray, O_CREAT | O_RDWR, 0400 | 0200);
if (dup2(outFD, STDOUT_FILENO) < 0)
{
perror("Last child's > dup2 failed");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (lastChildFlag == 1)
{
greaterthanSign = 0;
lastChildFlag = 0;
if (close(outFD) < 0)
{
perror("close on outFD failed");
exit(EXIT_FAILURE);
}
}
printf("Execvp last child\n");
if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0)
{
perror("Last child's execvp failed");
exit(EXIT_FAILURE);
}
printf("Last child execvp finished\n");
}
}
}
// Only the parent gets here
printf("Only the parent should be here\n");
printf("My pid is %d\n", getpid());
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
for (;;)
{
pid_t pid;
if (pid = wait(NULL) < 0)
{
perror("wait failed");
exit(EXIT_FAILURE);
}
if (pid == lastChild)
{
printf("Parent is waiting for lastChild\n");
break;
}
}
printf("Parent finished waiting. Returning...\n");
return 0;
}
I did pipe(fildes) before any fork, so that all children and a parent have their copy. Therefore, I must close all file descriptors in each child (after dup2 but before execvp) and the parent. The parent will then wait until it gets the pid of lastChild.
With a lot of printf statements, I have found that no child does the dup2() command (except for dup2(inFD...) and dup2(outFD...) when the flags are appropriate). There is also no error printed.
I printed out my (char) newargv[] and my (int) pipeArray[] and they contain the correct values. It seems to be just the dup2 problem, and I have absolutely no idea what's going wrong with it.
I made a simple text file called test2 containing
ls | sort | cat someString
Where someString is just a file with some text. With all the print statements in the pipeHandler() function my output is:
EDIT: I fixed a couple typos I had. I forgot to lace an extra set of parenthesis on 3 ifs, if ((firstChild = fork()0 < 0)
I now have an infinite loop as the parent is waiting for the lastChild's pid. Here's the output:
Initializing pipes
numpipes = 2
pipe initializing; i is 0
pipe initializing; i is 2
firstChild pid = 20521
firstChild pid = 20522
doing dup2 fildes[writeDes]
middleChild pid = 20521
middleChild pid = 20523
lastChild pid = 20521
Only the parent should be here
My pid is 20521
lastChild pid = 20524
<infinite loop>
I'm still clueless though as to what's going on or what's potentially stopping the child.
#MarkPlotnick you're right! It's not that dup2 isn't executing or anything. Because I did dup2(fildes[1], STDOUT_FILENO), all print statements will be piped.
I fixed the typo mentioned as well. I tried my teacher's test file
< input1 cat|>your.outputc tr a-z A-Z | tr \ q
Which should result with a file called your.outputc. It does, and the contents are input1 with the effects of tr. However, I also have the printf statements at the top of this file.
I assumed the dup2 wasn't working because no printf statement followed, unlike it did in dup2(inFD, STDIN_FILENO), but that's probably because it was STDIN.

I am having trouble redirecting my output back from file to standard out C

I have looked all over the internet and die.net and can't see to make my code work. My problem is that I am able to redirect the output to a file, but have trouble bringing it back to standard out, I have tried using dup, dup2 and close, but maybe I am using them wrong. Any help would be appreciated, thank you
. My problem begins at the if(myargc >= 3) block when I am trying to redirect the output.
main()
{
int i, myargc =0, background, newfile, file, stdout2, read = 0, write = 0;
pid_t pid;
char input[512], *myargv[60];
while(1)
{
background = 1;
printf("Myshell>");
gets(input);
//scanf("%s", input);
myargc = parser(input, myargv);
if(strcmp(*myargv, "exit") == 0)
{
exit(0);
}
if(strcmp(myargv[myargc-1], "&") == 0)
{
background = 0;
myargv[myargc-1] = '\0';
myargc--;
}
if(myargc >= 3)
{
if(strcmp(myargv[myargc-2], ">") == 0)
{
write = 1;
file = creat(myargv[myargc-1], S_IWUSR);
myargv[myargc-2] = '\0';
if(file < 0)
{
printf("File could not be created.\n");
}
printf("Redirecting output to file %s.\n", myargv[myargc-1]);
fflush(stdout);
stdout2 = dup(STDOUT_FILENO);
//fclose(stdout); // fclose() for type FILE*
newfile = dup2(file, 1); // uses lowest number descriptor (1, since just
// closed stdout)
close(file); // closes old file descriptor duplicate, close() uses int
myargc = myargc-2;
}
}
if ((pid = fork()) == -1 )
{
// if fork fails, print error and exit
perror("Fork failed");
exit(-1);
}
else if (pid == 0) { // child process
if (read == 0 && write == 0)
{
printf("This is the child ready to execute: ");
fflush(stdout);
for (i =0; i < myargc; i++)
{
printf("%s ", myargv[i]);
fflush(stdout);
}
printf("\n");
}
if (execvp(*myargv,myargv) < 0);
{
printf("Execution failed.");
}/* error exit - exec returned */
close(newfile);
dup2(stdout2, STDIN_FILENO);
//close(file);
//if (close(file) == 0)
//{
//dup2(newfile, STDOUT_FILENO);
//close(newfile);
//close(stdout2);
// printf("Reopened stdout\n");
// }
perror("Exec returned");
exit(-1);
}
close(newfile);
if (background == 1) { /* this is the parent -- wait for child to terminate */
wait(pid,0,0);
printf("The parent is exiting now\n");
}else{
waitpid(pid, NULL, WNOHANG); //returns immediately, no wait
}
//test for correct parsing
printf("myargv:\n");
for (i = 0; i < myargc; i++)
{
printf("%s\n", myargv[i]);
}
printf("myargc: %d\n", myargc);
// clear out buffers
memset(&myargv[0], 0, sizeof(myargv));
memset(&input[0], 0, sizeof(input));
}
}

Resources