Reputation: 63
Trying to implement my own linux shell with a few basic functions and of course an issue comes when it's time to implement the pipes. To be more specific the piping works for the most part, though it seems to drop the last argument. For example if I were to run the command
ps ax | grep ps
The ps after the grep command is dropped in my shell. So instead of outputting this as shown using your typical Linux shell
339 ? S 0:00 upstart-udev-bridge --daemon
497 ? Ss 0:00 /usr/sbin/cupsd -F
503 ? S< 0:00 [kpsmoused]
720 ? S 0:00 upstart-socket-bridge --daemon
5541 pts/0 R+ 0:00 ps ax
5542 pts/0 S+ 0:00 grep --colour=auto ps
You get this
339 ? S 0:00 upstart-udev-bridge --daemon
497 ? Ss 0:00 /usr/sbin/cupsd -F
503 ? S< 0:00 [kpsmoused]
720 ? S 0:00 upstart-socket-bridge --daemon
5557 pts/0 R+ 0:00 ps ax
In this case you're not searching for the matching pattern ps.
The function for piping runs as follows
void mypipes(char* args[], int nargs)
{
pid_t pid;
int fd[2];
char* cmdargs[nargs - 2];
char* cmdargs2[nargs - 2];
int i;
int t = 0;
int count = 0;
for(i = 0; i < nargs; i++)
{
if(!strcmp(args[i], "|"))
{
//dont put into array
t = 1;
}
else if(t == 0)
{
cmdargs[i] = args[i];
count++;
}
else if(t == 1)
{
cmdargs2[i - 3] = args[i];
}
}
if(count == 2)
{
pipe(fd);
pid = fork();
if(pid == -1)
{
perror("unable to fork");
exit(1);
}
if(pid > 0)
{
wait(&pid);
close(fd[1]);
close(0);
dup2(fd[0],0);
execlp(cmdargs2[0], cmdargs2[0], cmdargs2[1], NULL);
}
if(pid == 0)
{
close(fd[0]);
close(1);
dup2(fd[1],1);
execlp(cmdargs[0], cmdargs[0], cmdargs[1], NULL);
}
}
if(count == 1)
{
pipe(fd);
pid = fork();
if(pid == -1)
{
perror("unable to fork");
exit(1);
}
if(pid > 0)
{
wait(&pid);
close(fd[1]);
close(0);
dup2(fd[0],0);
execlp(cmdargs2[0], cmdargs2[1], NULL);
}
if(pid == 0)
{
close(fd[0]);
close(1);
dup2(fd[1],1);
execlp(cmdargs[0], cmdargs[1], NULL);
}
}
}
I've checked to see if all the variables after the pipe are still within the second set of arguments and they are the issue isn't the main but somewhere where I'm executing the actual piping where it doesn't read to the end.
Thank you in advance for any tips on what could be wrong here.
Upvotes: 2
Views: 1617
Reputation: 2970
First, unless I'm missing something, your two sample ouputs both look like they're working: they both only list lines with 'ps' in them. (If it really was running ps ax | grep
then grep
would complain about usage). The only difference I can see in the outputs is that the second doesn't list the grep
process itself, but this can easily happen if the ps
has finished grabbing the process-list before the grep
is started.
Second, your use of wait(&pid)
is odd -- as it's in the child process, it will wait for any of the child-process's children to exit. As there are none, it will return ECHILD
(and if there were, it would overwrite pid
with the grandchild's exit status).
Third, your use of t
, cmdargs
and cmdargs2
together with count
to decide which execlp
call to make only works if it's of the form cmd1 arg1 | cmd2 arg2
-- almost any other combinaation won't work. A couple of points:
[i -3]
to save the arguments after the pipe, you need to remember at which position you saw the pipe (e.g. instead of t=1
, use t=i+1
when you find the pipe and cmdargs2[i-t]
when saving the arguments after it).execvp()
version of the function call, so that you can pass in arrays of arguments (remembering to add a NULL element after all the ones from the command-line).Upvotes: 1