Reputation: 2124
I've written my own shell in C, and when I run ls | grep .c
, I get nothing. Although unpiped commands are working fine, like ls
. Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "shell.h"
#include "builtins.h"
#include "makeargv.h"
void shell()
{
pid_t shell_pid;
int i;
int flag = 1;
int argc0;
int argc1;
int fdl[2];
int fdr[2];
size_t input_size;
char cwd[128]; //this is being toggled
char *delim0;
char *delim1;
char *lastarg;
char *input;
char *debugdescriptor;
char **argvp;
char **firstargs;
shell_pid = getpid();
do
{
// Retrieve PID & CWD of the parent process.
getcwd(cwd, (128 * sizeof(char)));
printf("{%i}%s$ ", shell_pid, cwd);
// Retrieve input from stdin.
input = NULL;
input_size = 0;
getline(&input, &input_size, stdin);
//seperates the input into pipe-delimited arguments("tokens")
delim1 = "|\n";
argc1 = makeargv(input, delim1, &argvp);
//got some debugging tools here
//debugdescriptor = "PIPE-SEPERATED";
//debug_args(&argvp, &argc1, debugdescriptor);
//check for quit and cd first
delim0 = " ";
argc0 = makeargv(argvp[0], delim0, &firstargs);
//more debugging tools here
//debugdescriptor = "FIRST ARGS";
//debug_args(&firstargs, &argc0, debugdescriptor);
//exit
if((i = strcmp(firstargs[0],"exit")) == 0 || (i = strcmp(firstargs[0],"quit")) == 0)
{
printf("===========SHELL TERMINATED==============\n\n");
flag = 0;
}
//cd
else if((i = strcmp(firstargs[0],"cd")) == 0)
{
chdir(firstargs[1]);
}
else // Create a child process to handle user input.
{
char **thisarg;
int childlayer = 0;
pid_t pid = fork();
wait(0);
if(pid == 0)
childlayer++;
int tokens = argc1 - 1;
if(argc1 == 1 && pid == 0)
{
makeargv(argvp[tokens], delim0, &thisarg);
execvp(thisarg[0], thisarg);
}
else //more than 1 arguement, (has pipes)
{
while(pid == 0 && childlayer < argc1){
if(childlayer == 1){ //rightmost
pipe(fdl);
pid = fork();
wait(0);
if(pid == 0)
childlayer++;
if(pid > 0){
close(fdl[1]);
dup2(fdl[0], STDIN_FILENO); //sets the final output to write to STDIN
execute(childlayer, argc1, &argvp);
}
}
else if(childlayer > 1 && childlayer < argc1-1){ //middle args
pipe(fdr);
fdr[1] = fdl[1];
fdr[0] = fdl[0];
dup2(fdr[1], STDOUT_FILENO);
pipe(fdl);
pid = fork();
wait(0);
if(pid == 0)
childlayer++;
if(pid > 0){
close(fdl[1]);
dup2(fdl[0], STDIN_FILENO);
execute(childlayer, argc1, &argvp);
}
}
else{ //leftmost
pipe(fdr);
fdr[0] = fdl[0];
fdr[1] = fdl[1];
close(fdr[0]);
dup2(fdr[1], STDOUT_FILENO);
execute(childlayer, argc1, &argvp);
}
}
}
}
}while(flag == 1);
}
I think I may be getting stuck in a child process when I use the pipes, but I haven't been able to see where. Thanks.
Upvotes: 0
Views: 402
Reputation: 12749
Why do you wait(0)
immediately after fork()
? In the child, this will return immediately with an error, but in the parent, it will block until the child exits. I'm having a hard time following how the pipeline is established because each child is forking off the next child in the pipeline. I'm guessing the wait(0)
is creating a chicken-and-egg problem; the parent can't start until the child exits, but the child can't exit because it needs input from the parent. Wouldn't it be simpler if the shell process just looped over the pipeline components and forked each one itself, and then waited for them all to finish?
Upvotes: 1
Reputation: 212198
You are almost certainly failing to close all your file descriptors. One source of such an error is your dup2
calls.
After:
dup2(fdr[1], STDOUT_FILENO);
you should call
close(fdr[1]);
Upvotes: 3