2016-03-18 2 views
1

читатель. Я пишу программу на C, которая имитирует оболочку linux. Перед внедрением трубопроводов мой код работал нормально, а также на выходных/входных файлах. Далее выполнялся командный трубопровод, такой как (a | b) | c. Ниже мой код:Реализация трубопроводов для имитации Shell

Проверяя его, я получаю правильные результаты для «sfhjdj», «exit» и «cd». Проблема в том, что простая команда возвращает ls: write error: Bad file descriptor. Попытка трубы также выполняет первую функцию. Любая идея о том, что вызывает это? Я попытался трубить, как я видел из других вопросов здесь.

Ниже мой код перед внедрением трубопровода, я не могу найти ошибку, но может быть из-за закрытия/обмана. Спасибо за чтение этого!

Только изменение было в функции выполнения.

EDIT: Helper код, prase.c

/* 
* parse.c - feeble command parsing for the Feeble SHell. 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 
#include <string.h> 
#include "parse.h" 
#include "error.h" 


#define MAXARGV 1000 

enum token { 
    identifier, directin, directout, doubledirectout, 
    /* everything >= semicolon ends an individual "struct pipeline" */ 
    semicolon, 
    ampersand, 
    verticalbar, doubleampersand, doublebar, doublepipe, 
    eol 
}; 
static enum token gettoken(char **s, char **argp); 
static char *ptok(enum token tok); 


struct parsed_line *parse(char *s) 
{ 
    struct parsed_line *retval; /* remains freeparse()able at all times */ 
    struct parsed_line *curline; 
    struct pipeline **plp; /* where to append for '|' and '|||' */ 
    char *argv[MAXARGV]; 
    enum token tok; 
    int argc = 0; 
    int isdouble = 0; 

    retval = curline = emalloc(sizeof(struct parsed_line)); 
    curline->conntype = CONN_SEQ; /* i.e. always do this first command */ 
    curline->inputfile = curline->outputfile = NULL; 
    curline->output_is_double = 0; 
    curline->isbg = 0; 
    curline->pl = NULL; 
    curline->next = NULL; 
    plp = &(curline->pl); 

    do { 
     if (argc >= MAXARGV) 
      fatal("argv limit exceeded"); 
     while ((tok = gettoken(&s, &argv[argc])) < semicolon) { 
      switch ((int)tok) { /* cast prevents stupid warning message about 
            * not handling all enum token values */ 
      case identifier: 
       argc++; /* it's already in argv[argc]; 
          * increment to represent a save */ 
       break; 
      case directin: 
       if (curline->inputfile) { 
        fprintf(stderr, 
          "syntax error: multiple input redirections\n"); 
        freeparse(curline); 
        return(NULL); 
       } 
       if (gettoken(&s, &curline->inputfile) != identifier) { 
        fprintf(stderr, "syntax error in input redirection\n"); 
        freeparse(curline); 
        return(NULL); 
       } 
       break; 
      case doubledirectout: 
       curline->output_is_double = 1; 
       /* fall through */ 
      case directout: 
       if (curline->outputfile) { 
        fprintf(stderr, 
          "syntax error: multiple output redirections\n"); 
        freeparse(curline); 
        return(NULL); 
       } 
       if (gettoken(&s, &curline->outputfile) != identifier) { 
        fprintf(stderr, "syntax error in output redirection\n"); 
        freeparse(curline); 
        return(NULL); 
       } 
       break; 
      } 
     } 

     /* cons up just-parsed pipeline component */ 
     if (argc) { 
      *plp = emalloc(sizeof(struct pipeline)); 
      (*plp)->next = NULL; 
      (*plp)->argv = eargvsave(argv, argc); 
      (*plp)->isdouble = isdouble; 
      plp = &((*plp)->next); 
      isdouble = 0; 
      argc = 0; 
     } else if (tok != eol) { 
      fprintf(stderr, "syntax error: null command before `%s'\n", 
        ptok(tok)); 
      freeparse(curline); 
      return(NULL); 
     } 

     /* ampersanded? */ 
     if (tok == ampersand) 
      curline->isbg = 1; 

     /* is this a funny kind of pipe (to the right)? */ 
     if (tok == doublepipe) 
      isdouble = 1; 

     /* does this start a new struct parsed_line? */ 
     if (tok == semicolon || tok == ampersand || tok == doubleampersand || tok == doublebar) { 
      curline->next = emalloc(sizeof(struct parsed_line)); 
      curline = curline->next; 

      curline->conntype = 
       (tok == semicolon || tok == ampersand) ? CONN_SEQ 
       : (tok == doubleampersand) ? CONN_AND 
       : CONN_OR; 
      curline->inputfile = curline->outputfile = NULL; 
      curline->output_is_double = 0; 
      curline->isbg = 0; 
      curline->pl = NULL; 
      curline->next = NULL; 
      plp = &(curline->pl); 
     } 

    } while (tok != eol); 
    return(retval); 
} 


/* (*s) is advanced as we scan; *argp is set iff retval == identifier */ 
static enum token gettoken(char **s, char **argp) 
{ 
    char *p; 

    while (**s && isascii(**s) && isspace(**s)) 
     (*s)++; 
    switch (**s) { 
    case '\0': 
     return(eol); 
    case '<': 
     (*s)++; 
     return(directin); 
    case '>': 
     (*s)++; 
     if (**s == '&') { 
      (*s)++; 
      return(doubledirectout); 
     } 
     return(directout); 
    case ';': 
     (*s)++; 
     return(semicolon); 
    case '|': 
     if ((*s)[1] == '|') { 
      *s += 2; 
      return(doublebar); 
     } 
     (*s)++; 
     if (**s == '&') { 
      (*s)++; 
      return(doublepipe); 
     } 
     return(verticalbar); 
    case '&': 
     if ((*s)[1] == '&') { 
      *s += 2; 
      return(doubleampersand); 
     } else { 
      (*s)++; 
      return(ampersand); 
     } 
    /* else identifier */ 
    } 

    /* it's an identifier */ 
    /* find the beginning and end of the identifier */ 
    p = *s; 
    while (**s && isascii(**s) && !isspace(**s) && !strchr("<>;&|", **s)) 
     (*s)++; 
    *argp = estrsavelen(p, *s - p); 
    return(identifier); 
} 


static char *ptok(enum token tok) 
{ 
    switch (tok) { 
    case directin: 
     return("<"); 
    case directout: 
     return(">"); 
    case semicolon: 
     return(";"); 
    case verticalbar: 
     return("|"); 
    case ampersand: 
     return("&"); 
    case doubleampersand: 
     return("&&"); 
    case doublebar: 
     return("||"); 
    case doubledirectout: 
     return(">&"); 
    case doublepipe: 
     return("|&"); 
    case eol: 
     return("end of line"); 
    default: 
     return(NULL); 
    } 
} 


static void freepipeline(struct pipeline *pl) 
{ 
    if (pl) { 
     char **p; 
     for (p = pl->argv; *p; p++) 
      free(*p); 
     free(pl->argv); 
     freepipeline(pl->next); 
     free(pl); 
    } 
} 


void freeparse(struct parsed_line *p) 
{ 
    if (p) { 
     freeparse(p->next); 
     if (p->inputfile) 
      free(p->inputfile); 
     if (p->outputfile) 
      free(p->outputfile); 
     freepipeline(p->pl); 
     free(p); 
    } 

builtin.c - для компакт-диска и выхода

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include "fsh.h" 
#include "builtin.h" 


int builtin_exit(char **argv) 
{ 
    if (argv[1] && argv[2]) /* i.e. argc >= 2 */ { 
     fprintf(stderr, "usage: exit [status]\n"); 
     fflush(stderr); 
     return(1); 
    } else if (argv[1]) { 
     /* "exit ###" */ 
     exit(atoi(argv[1])); 
    } else { 
     /* "exit" with no argument */ 
     exit(laststatus); 
    } 
} 

int builtin_cd(char **argv) 
{ 
    if (argv[1] && argv[2]) { 
     fprintf(stderr, "usage: %s dir\n", argv[0]); 
     return(1); 
    } else if (argv[1]) { 
     chdir(argv[1]); 
    } else { 
     chdir(getenv("HOME")); 
    } 
    //if (chdir(argv[1])) { 
    // perror(argv[1]); 
    // return(1); 
    //} 
    return(0); 
} 

Parse.h - как трубопровод

enum connenum { 
    CONN_SEQ, /* sequential commands, i.e. separated by a semicolon */ 
    CONN_AND, /* commands joined by '&&' */ 
    CONN_OR /* commands joined by '||' */ 
}; 

struct pipeline { /* list of '|'-connected commands */ 
    char **argv; /* array ending with NULL */ 
    struct pipeline *next; /* NULL if this doesn't pipe into anything */ 
    int isdouble; /* 1 if we have '|&' i.e. should dup onto 2 */ 
}; 

struct parsed_line { /* list of ';' or '&&' or '||' -connected struct pipelines */ 
    enum connenum conntype; /* will be CONN_SEQ if this is the first item */ 
    char *inputfile, *outputfile; /* NULL for no redirection */ 
    int output_is_double; /* output redirection is '>&' rather than '>' */ 
    struct pipeline *pl; /* the command(s) */ 
    int isbg; /* non-zero iff there is a '&' after this command */ 
    struct parsed_line *next; /* connected as specified by next->conntype */ 
}; 


extern struct parsed_line *parse(char *s); 
extern void freeparse(struct parsed_line *p); 
+0

Код не компилируется. Вы можете получить дополнительную помощь, если вы разместите [mcve]. –

+0

@terencehill Программа имеет несколько вспомогательных файлов, хотя сама функция execute больше не используется. Я обновил сообщение с помощью некоторого кода. –

+0

Это не совсем mcve. Вы должны попытаться сделать минимальный пример, который воспроизводит ошибку. –

ответ

1

СсылкаCreating Pipes in C

RefGNU Pipe to a Subprocess

Может помочь вам, если вы действительно хотите, чтобы добраться до забоя.

Это может помочь вам, если вы предпочитаете использовать POPEN

RefPipes the Easy Way using popen

Я испытание это и делает то, что вы хотите Например, открывается 2 трубы (низкоспиновое и сортировки команд) Обратите внимание на атрибут r в popen («ls», «r»), который, как я подозревал, мог быть проблемой с вышеуказанным кодом.

Например

Если родитель хочет получить данные от ребенка, он должен близко fd1, и ребенок должен близко fd0. Если родитель хочет отправить данные ребенку, он должен закрыть fd0, и ребенок должен закрыть fd1.

Поскольку дескрипторы разделены между родителем и дочерним элементом, мы всегда должны быть уверены, что мы закрываем конец трубы, с которым мы не связаны. В техническом примечании EOF никогда не будет возвращен, если ненужные концы трубы не будут явно закрыты.

Файл дескриптора для трубы не могут быть установлены в Чтение/Запись или файла дескрипторы закрыты в правильном порядке ..

#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    FILE *pipein_fp, *pipeout_fp; 
    char readbuf[80]; 

    /* Create one way pipe line with call to popen() */ 
    if ((pipein_fp = popen("ls", "r")) == NULL) 
    { 
      perror("popen"); 
      exit(1); 
    } 

    /* Create one way pipe line with call to popen() */ 
    if ((pipeout_fp = popen("sort", "w")) == NULL) 
    { 
      perror("popen"); 
      exit(1); 
    } 

    /* Processing loop */ 
    while(fgets(readbuf, 80, pipein_fp)) 
      fputs(readbuf, pipeout_fp); 

    /* Close the pipes */ 
    pclose(pipein_fp); 
    pclose(pipeout_fp); 

    return(0); 
} 

Если вам нужно Parsing Program Arguments

Getopt: Разбор программ с использованием getopt.

Argp: Параметры программы-анализа с использованием argp_parse.

Суппозитории: Некоторые программы требуют более подробных сведений.

Может помочь вам.

Все самое лучшее

Смежные вопросы