2011-04-18 63 views
0

虽然我的程序在所有情况下都能正常工作,但它们不会使用管道将两个命令中的第一个命令的输出连接到第二个命令的输出时,它们被管道符号分隔。我将第一个命令的输出写入文件,然后在运行该命令的进程运行时将第二个命令的标准输入重定向到文件。我需要使用管道系统调用来创建管道并获取管道的文件描述符 ,然后同时运行这两个进程。这是一个家庭作业问题,我完成了99%的工作,但不知何故无法使管道系统调用正常工作......我一直在尝试的是如下输入:Command 1 |在命令2的子进程中关闭命令2 I关闭FD [0],然后关闭FD [1],命令1关闭FD [1],然后关闭FD [1]并关闭FD [0]。在迷你外壳中使用管道系统调用

我是地狱使用管道时使用的文件描述符困惑....我一定要使用管道

任何形式的帮助表示赞赏。执行功能是我分叉进程的地方。

这里是我的代码...

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <regex.h> 

/* Global Variables */ 
extern char **environ;  /* Environmental Variables */ 
char *pathList[10];   /* List of paths from the $PATH */ 
int pathCount;   /* Count of the # of paths in $PATH */ 
char *pathSet;   /* Variable through which $PATH is retrieved */ 
int hasPipe = 0; 
int cmdNo = 0; 


/* This function takes the 'finalPath', the full path to executable,argList[],the 
    full command-line input arguments and argCount, the number of arguments from 
    command-line as input. It the creates a child process, in turn invokes the 
    execve() that finally executes the executable in 'finalPath' with the arguments 
    in 'argText' all stored into the args[] appropriately. Child process also handles 
    input and output file re-direction. 
    */ 


void execute(char *finalPath, char *argList[], int argCount) 
{ 
    int k,fd,ofound,pos,i;   /* flags and temporary variables */ 
    pid_t pid;     /* process ID */ 
    int status, which; 
    char msg[100]; 
    char *args[4];     /* argument list for execve() */ 
    int spCase = 0; 
    ofound = 0; 
    pos=0; 
    pid = fork();     /* Creating a new process using fork() */ 
    if (pid == -1)     /* Checking for errors in process creation */ 
    { 
     write(1,"Fork failed.\n",12); 
     exit(1); 
    } 

    /************************** 
     Checking for parent process 
    ***************************/ 
    if (pid != 0) 
    { 
     which = wait(&status); 
     if (which == -1) 
     { 
      write(1,"Wait failed.\n",12); 
      exit(1); 
     } 
     if (status & 0xff) 
     { /* Case of abnormal termination */ 
      sprintf(msg,"ERROR: <dShell> # process %d terminated abnormally for reason %d\n",which, status & 0xff); 
      write(1,msg,strlen(msg)); 
     } 
     else 
     { /* Case of normal termination */ 
      sprintf(msg,"process %d terminated normally with status %d\n",which, (status >> 8) & 0xff); 
      write(1,msg,strlen(msg)); 
     } 

    } 

    /************************* 
     Checking for child process 
    **************************/ 
    if (pid == 0) 
    { 
     char argText[50]; 
     argText[0] = '\0'; 
     int std_fd; 
     if(cmdNo==0 && hasPipe) 
     { 
      close(1); 
      std_fd = open("temp.out", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU); 
      dup(std_fd); 
     } 
     else if(cmdNo==1 && hasPipe) 
     { 
      close(0); 
      std_fd = open("temp.out", O_RDONLY); 
      dup(std_fd); 
     } 

     /* Finding the first re-direction operator */ 
     for(i = 0; i < argCount ; ++i) 
     { 
      if(ofound != 1 && ofound != 2) 
      { 
       if(strcmp(argList[i],"<") == 0) 
       { 
        fd = open(argList[i+1],O_RDONLY); 
        if (fd < 0) 
        { 
         sprintf(msg,"ERROR: %s could not be opened\n", argList[i+1]); 
         write(1, msg, strlen(msg)); 
         exit(5); 
        } 
        ofound = 1; 
        strcpy(argText,"\0"); 
        close(0); 
        dup(fd); 
        close(fd); 
       } 
       else if(strcmp(argList[i],">") == 0) 
       { 
        fd = open(argList[i+1],O_CREAT | O_WRONLY, 0777); 
        pos = i; 
        ofound = 2; 
        strcpy(argText,"\0"); 
        if (fd < 0) 
        { 
         sprintf(msg,"ERROR: %s could not be opened\n", argList[i+1]); 
         write(1, msg, strlen(msg)); 
         exit(5); 
        } 
        close(1); 
        dup(fd); 
        close(fd); 
       } 
      } 

     } 

     /* If input re-direction operator is found check for an output re-direction along with it */ 
     if(ofound == 1) 
     { 
      for(k = 0; k < argCount && ofound != 2; ++k) 
      { 
       if(strcmp(argList[k],">") == 0) 
       { 
        fd = open(argList[k+1],O_CREAT | O_WRONLY , 0777); 
        spCase = 1; 
        ofound = 2; 
        strcpy(argText,"\0"); 
        if (fd < 0) 
        { 
         sprintf(msg,"ERROR: %s could not be opened\n", argList[k+1]); 
         write(1, msg, strlen(msg)); 
         exit(5); 
        } 
        close(1); 
        dup(fd); 
        close(fd); 
       } 
      } 
     } 
     /* If the re-direction operators are not found */ 
     if(ofound == 0) 
     { 
      for(i = 1; i < argCount; ++i) 

      { 
       strcat(argText, argList[i]); 
       strcat(argText, " "); 
      } 
      spCase = 2; 

     } 

     /* Case when both arguments and output re-direction operators are found */ 
     if (spCase == 0) 
     { 
      if(pos == 0) 
      { 
       for(i = 3; i<argCount; ++i) 
       { 
        strcat(argText, argList[i]); 
        strcat(argText," "); 
       } 
      } 
      if(pos == argCount - 2) 
      { 
       for(i = 1; i<argCount - 2; ++i) 
       { 
        strcat(argText, argList[i]); 
        strcat(argText," "); 
       } 
      } 

     } 

     argText[strlen(argText)-1] = '\0'; /*because I added an extra space so trimming that*/ 
     /* Running the execve */ 
     args[0] = finalPath; 
     if(strlen(argText) == 0) /* checking if argText is populated */ 
     { 
      args[1] = NULL; 
     } 
     else 
     { 
      args[1] = argText; 
      args[2] = NULL; 
     } 

     /* Execute command,if it returns that means it failed and need to display error and exit */ 
     execve(args[0], args, environ); 
     sprintf(msg, "ERROR! execve() failed"); 
     write(1, msg, strlen(msg)); 
    } 

} 



/******************************************************************************* 
    This function checks if the path is accessible and continues to execute the 
    command. If the path does not exist of is not accessible, variable 'retFlag' 
    is used to return 0 to the calling function. 
********************************************************************************/ 

int checkPath(char *exepath, char *argList[], int argCount, int flag) 
{ 
    char *finalPath; 
    int retFlag = flag; 
    if(access(exepath,X_OK) == 0) 
    { 
     finalPath = exepath; 
     retFlag = 1; 
     execute(finalPath,argList,argCount); 
     return retFlag; 

    } 
    else 
     return retFlag; 
} 



/********************************************************************************** 
    This function checks if the first argument is a path and if so calls checkPath(). 
    Else it gets the paths set to the $PATH variable, tokenizes it, pads it with the 
    first token of input command and calls checkPath(). If the correct path is established, 
    the variable 'found' is used to kick out of the for loop. 
************************************************************************************/ 

void setPath(char *argList[], int argCount) 
{ 
    char *exepath; 
    char com[50]; 
    char emsg[80]; 
    char *command; 
    int i,found = 0; 

    /* Seperating the command if redirection is used */ 
    if(strcmp(argList[0],"<") == 0 || strcmp(argList[0],">") == 0) 
    { 
     command = argList[2]; 
    } 
    else 
     command = argList[0]; 

    /* In case of no redirection, storing the commands and arguments into a array */ 
    if(strcmp(command,"#") == 0) /* Checking for comment statements */ 
    { 
     write(1,"ERROR: No command(s) found. Only comment present/n",48); 
    } 
    else 
    { 
     if(strstr(command,"/"))   /* Checking if the entire path is given as a part of the command */ 
     { 
      exepath = command; 
      found = checkPath(exepath,argList,argCount,0); 
     } 
     else      /* building the path and storing it in 'com' */ 
     { 
      for(i = 0; i< pathCount && found != 1; i++) 
      { 
       sprintf(com,"%s%s%s",pathList[i],"/",command); 
       exepath = com; 
       found = checkPath(exepath,argList,argCount,0); 
      } 
     } 
     if(found == 0) 
     { 
      sprintf(emsg,"%s%s",command,":COMMAND DOES NOT EXIST"); 
      write(1,emsg,sizeof(emsg)); 
      write(1,"\n",1); 
     } 
    } 
} 

/* Tokenizes commands into words */ 
void tokens(char *cmdStr) 
{ 
    char cmd[100]; 
    strcpy(cmd,cmdStr); 
    char *result; 
    char delims[] = " ,  "; 
    char *argList[20]; 
    int argCount = 0; 

    /*Tokenize the individual command into strings */ 
    result = strtok(cmd,delims); 
    while(result != NULL) 
    { 
     argList[argCount] = result; 
     result = strtok(NULL, delims); 
     ++argCount; 
    } 
    setPath(argList,argCount); 

} 


/* Tokenizes multiple commands into single commands */ 
void tokenize(char *inputStr) 
{ 
    int i,cmdCount = 0; 
    char *cmdResult; 
    char *cmdStr[100]; 
    char delimiters[] = "|"; 
    cmdResult = strtok(inputStr, delimiters); 

    while(cmdResult != NULL) 
    { 
     cmdStr[cmdCount]=cmdResult; 
     cmdResult = strtok(NULL, delimiters); 
     cmdCount++; 
    } 

    if(cmdCount > 1)  
     hasPipe = 1; 
    else 
     hasPipe = 0; 

    for(i=0; i<cmdCount ; i++) 
    { 
     cmdNo = i%cmdCount; 
     tokens(cmdStr[i]); 
    } 
} 


int main(int argc, char *argv[]) 
{ 
    char prompt[8];   /* String that stores the personalized prompt */ 
    char *path;    /* Temporary variable used for tokenization*/ 
    char ch;   /* Temporary variable used in read() */ 
    int chCount;   /* # of characters read from the prompt */ 
    int entry;   /* return variable of read() */ 
    int flag;   /* Flag to go read the next command when newline is found */ 
    regex_t reIgnore; 
    char pattern[20]="^\\s*$|^#.*"; 

    /* Tokenizing the paths asociated with the $PATH and storing them in a array declared globally */ 

    pathCount = 0; 
    pathSet = getenv("PATH"); 
    if (!pathSet) 
    { 
     write(1, "ERROR: PATH environment does not exist.\n", 40); 
     exit(1); 
    } 
    path = strtok(pathSet,":"); 
    while(path != NULL) 
    { 
     pathList[pathCount] = path; 
     path = strtok(NULL,":"); 
     ++pathCount; 
    } 

    /* Checks for blanks and tabs in Step 2 */ 
    if (regcomp(&reIgnore, pattern, REG_EXTENDED)) 
    { 
     write(1, "Error. \n",9); 
     exit(2); 
    } 

    sprintf(prompt,"<dShell> # ");   /* Storing the personalized shell prompt into 'prompt' */ 


    /* Reading the input from command line and passing it to tokenize() */ 
    while(1) 
    { 
     char inputStr[100];    /* String into which inputs are read into */ 
     chCount = 0; 
     flag = 0; 
     hasPipe = 1; 

     write(1,prompt,strlen(prompt));  /* Printing out the personalized shell prompt */ 

     /* This will read a character 1 by 1 until it reaches the end of file */ 
     entry = read(0,&ch,1); 
     if(!entry) 
      exit(0); 

     /* Reading the input and storing it in inputStr as long as newline is not encountered */ 
     while(entry != 0 && flag == 0) 
     { 
      /* A newline has been found so a new command will need to be executed */ 
      /* The inputStr till this point is sent to tokenize() */ 
      if(ch == '\n') 
      { 
       inputStr[chCount] = '\0'; 
       flag = 1; 
       if(chCount > 0) { 
        if(strcmp(inputStr,"exit") == 0) 
         exit(3); 
        else 
         tokenize(inputStr); 
       } 
      } 

      inputStr[chCount] = ch; 
      chCount++; 
      if(flag == 0) 
       entry = read(0, &ch, 1); 

     } 
    } 
} 

回答

1

管道参见手册页(2)。它有这样的例子:

#include <sys/wait.h> 
    #include <assert.h> 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <string.h> 

    int 
    main(int argc, char *argv[]) 
    { 
     int pipefd[2]; 
     pid_t cpid; 
     char buf; 

     assert(argc == 2); 

     if (pipe(pipefd) == -1) { 
      perror("pipe"); 
      exit(EXIT_FAILURE); 
     } 

     cpid = fork(); 
     if (cpid == -1) { 
      perror("fork"); 
      exit(EXIT_FAILURE); 
     } 

     if (cpid == 0) { /* Child reads from pipe */ 
      close(pipefd[1]);   /* Close unused write end */ 

      while (read(pipefd[0], &buf, 1) > 0) 
       write(STDOUT_FILENO, &buf, 1); 

      write(STDOUT_FILENO, "\n", 1); 
      close(pipefd[0]); 
      _exit(EXIT_SUCCESS); 

     } else {   /* Parent writes argv[1] to pipe */ 
      close(pipefd[0]);   /* Close unused read end */ 
      write(pipefd[1], argv[1], strlen(argv[1])); 
      close(pipefd[1]);   /* Reader will see EOF */ 
      wait(NULL);    /* Wait for child */ 
      exit(EXIT_SUCCESS); 
     } 
    } 
+0

感谢帮助! :) – DhawalV 2011-04-23 21:27:45