I am so close to figuring out a program I have been writing for linux shell written in C. I have been wanting to get this working for a while now, and I decided to pick it up again and have been tinkering with it for the past few weeks.
For the following code, keep in mind that the array called arrayOfCommands is dynamically filled. My code fills the arrayOfCommands with the current command being run. For the sake of my example, we will be running the command ls -l | wc and arrayOfCommands is filled with the following, depending on which time through the loop it is:
//Pass #1
arrayOfCommands[]= ("ls", "-l", NULL)
//Pass #2
arrayOfCommands[]= ("wc", NULL)
Here is what I have so far:
//PIPING
int do_command(char **args, int pipes) {
// pipes is the number of pipes in the command
// (In our example, one)
// The number of commands is one more than the
// number of pipes (In our example, two)
const int commands = pipes + 1; //Ex: 2
int i = 0;
// Set up the pipes
int pipefds[2*pipes];
for(i = 0; i < pipes; i++){
if(pipe(pipefds + i*2) < 0) {
perror("Couldn't Pipe");
exit(EXIT_FAILURE);
}
}
// Variables
int pid;
int status;
char *str_ptr;
int j = 0;
for (i = 0; i < commands; ++i) {
// A magic function that updates arrayOfCommands with
// the current command goes here. It doesn't make
// sense in the context of the code, so just believe me! :)
// Ex: The contents will be "ls -l" or "wc" depending on
// which time through the loop we are
pid = fork();
if(pid == 0) {
//if not last command
if(i < commands){
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
//if not first command&& j!= 2*pipes
if(j != 0 ){
if(dup2(pipefds[j-2], 0) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
for(i = 0; i < 2*pipes; i++){
close(pipefds[i]);
}
// Should any of the below inputs be *arrayOfCommands or
// **arrayOfCommands or &arrayOfCommands?
// I'm REALLY bad with pointers
if( execvp(arrayOfCommands, arrayOfCommands) < 0 ){
perror(arrayOfCommands);
exit(EXIT_FAILURE);
}
}
else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
j+=2;
}
for(i = 0; i < 2 * pipes; i++){
close(pipefds[i]);
}
for(i = 0; i < pipes + 1; i++){
}
wait(&status);
}
When I run this, I get a couple of errors:
Could someone help me figure out the following two things:
First thing:
//if not last command
if(i < commands)
should be
if(i < commands -1)
since i
goes from 0
to commands -1
that should solve dup2: Bad file descriptor
ls: |: No such file or directory
ls: wc: No such file or directory
are caused by malformed arrayOfCommands
. It has to be initialized by
char * arrayOfCommands[] = {"ls", "-l", NULL};
and
char * arrayOfCommands[] = {"wc", NULL};
respectively and invoked via execvp(arrayOfCommands[0], arrayOfCommands)
essentially arrayOfCommands
has to be of the same format that your argument vector (typically argv
) of an int main(int argc, char** argv)
.