C: piping and the redirect operator

Hi there,

So im having a bit of trouble here finishing up a program that involves the use of piping various unix commands in c. To be exact, I am struggling with how to make the redirect operator work.

Essentially the program it self will run a bunch of piped commands in c. For example you can give it the input:

ls -l | sort -n -r | head -n 3

and it should work as if you typed it into the terminal. My problem arises when I try to do:
ls -l | sort -n -r | head -n 3 > output.txt

My inital attempt was to search the string to see if the redirect operator existed. If so, then it would simply take some special branch where it could execute it, if not it would continue as if it did not exist. However my implementation to try this is shaky at best, so any explanation, help of what I should be doing would be greatly appreciated.

Code is attached below.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

/*get args function*/

#define MAXARGS 256
char ** getargs(char * cmd) {
	// assumes that cmd ends with NULL
	char** argsarray;
	int nargs = 0;
	int nlen = strlen(cmd);
	int i = 0;
	argsarray = (char**) malloc(sizeof(char*) * MAXARGS);
	argsarray[0] = strtok(cmd," ");
	i = 0;
	while (argsarray != NULL){
		i++;
		argsarray = strtok(NULL," ");
	}
	return argsarray;
}


int main(void){

  pid_t childpid;
  int fd[256][2];
  char cmd[256];
  char * sepCmd[256];
  char * pch;

  printf("Please enter a command sequence: \n");
  gets(cmd);
  //scanf("%s", cmd);
  printf("You have entered: %s \n", cmd);
  

  printf("Attempting to split up command: \n");
  pch = strtok (cmd, "|");
  

  /* My initial idea of how to tackle redirection
  char * srch;
  srch = strchr(cmd, '>');
  int reDir;

  while(cmd != NULL) {
  if (srch != NULL){
    printf("redirect operator found\n");
    reDir = 1;
          
  }
  srch = strchr(srch+1, '>');
  }
  */
  
  
  
  int count = 0;  
    while (pch != NULL && count < 256) {
      printf("%s\n", pch);
      sepCmd[count] = pch;
      printf("The value in this array value is: %s\n", sepCmd[count]);
      pch = strtok (NULL, "|");
      count++;
  }
  
  char ** argue;
  int k;
  
  /* Block that deals with the first command given by the user */
  k = 0;
  pipe(fd[k]);
  if(!fork()) {
	  	dup2(fd[k][1], STDOUT_FILENO);
		close(fd[k][0]);
		argue = getargs(sepCmd[k]);
		execvp(argue[0], argue);
		perror(argue[0]);
		exit(0);
  }

  /*Loop that will control all other comands except the last*/
  for(k = 1; k <= count - 2; k++) {
	  close(fd[k-1][1]);
	  pipe(fd[k]);
	  
	  if(!fork()) {
		  close(fd[k][0]);
		  dup2(fd[k-1][0], STDIN_FILENO);
		  dup2(fd[k][1], STDOUT_FILENO);
		  argue = getargs(sepCmd[k]);
		  execvp(argue[0], argue);
		  perror(argue[0]);
		  exit(0);
	  }
  }
  
  
  /*Block that will take care of the last command in the sequence*/
  k = count - 1;
  
  //  if(reDir){
  //argue = getargs(sepCmd[k]);
  //open(argue[count], O_RDWR);
    
  //if(!fork()){
  //  close(fd[0]);
  //  close(fd[1]);
  //  dup2(fd[k-1][0], STDOUT_FILENO);
  //  execl("/bin/>", argue[count]);}
  //}
  //else{
     
  close(fd[k-1][1]);
  if(!fork()) {
	  dup2(fd[k-1][0], STDIN_FILENO);
	  argue = getargs(sepCmd[k]);
	  execvp(argue[0], argue);
	  perror(argue[0]);
	  exit(0);
  }
  // }
  while(waitpid(-1, NULL, 0) != -1);
}

The professor's code is working without the redirection. To add redirection at the end, all you need to do is

locate the ">" position with: srch = strchr(cmd, '>');
terminate the cmd at that position: *srch++ = '\0'
advance srch to skip the ">" and blanks: while (*srch == ' ') ++srch;

before parsing the command line. Then open/create srch for writing and dup2 the fd with:

if (srch) dup2(open(srch, O_RDWR|O_CREAT), STDOUT_FILENO);

before execvp in the last child

Hi there,

This is the Original Poster (I had made the initial post on my partner's account). Anyways thank you for the reply! The code worked like a charm for the most part. Now it seems to only work when the redirect operator is present in the user inputted commands. Im guessing this is due to my placing of the first chunk of code you had posted. In my code that snipped is currently placed right before:

while (pch != NULL && count < 256) {

This is the location you had intended?

Thanks in advance

---------- Post updated 10-29-09 at 10:57 AM ---------- Previous update was 10-28-09 at 11:51 PM ----------

So a little update,

I changed gets to fgets and it seems like it will take any amount of comannds piped together, but only if it ends with a redirection operator or else I get errors like:

<COMMAND>: invalid option -- '

where COMMAND is the last command in the sequence