2016-12-07 9 views
-1

Это мой первый вопрос, поэтому я приношу свои извинения, если я опускаю что-то важное. Поэтому я работал над заданием, которое обрабатывает трубопроводы с помощью форкирования. Мой код довольно грязный, усеянный заявлениями printf, поэтому я вижу, что происходит.C - dup2() не исполняется

Я огляделся в Интернете, и я думаю, что получаю представление о том, как обрабатывать трубопроводы, но проблема, с которой я сталкиваюсь, заключается в том, что мой код пропускает dup2() для любого файлового дескриптора, кроме inFD и outFD.

Вот код моей функции. Кроме того, из того, что я понимаю, мой учитель сделал макрос CHK, который проверяет наличие ошибок. Если есть ошибка (например, dup2, возвращающая -1), она завершается печатью stderr.

Мои включает в себя, глобальные переменные и MyHandler() для сигнала

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/wait.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <strings.h> 
#include <math.h> 
#include <signal.h> 

// Function calls 
void parse(char *w, char **ptrArray, char *inArray, char *outArray, int *pipeArray); 
int flagHandler(char **ptrArray, char *inArray, char *outArray); 
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray); 

// Global Variables 
const int STORAGE = 254; 
const int MAXITEM = 100; 
int inFD; // file descriptor for < 
int outFD; // file descriptor for > 
int complete = 0; // for sighandler 
int readDes = 0; 
int writeDes = 1; 
int numPipes = 0; 
int status; 
int forCounter = 0; 

int fildes[4]; 
int pipeIndex = 0; 

// MetaChar flags 
int lessthanSign = 0; // < flag 
int greaterthanSign = 0; // > flag 
int firstChildFlag = 0; 
int lastChildFlag = 0; 

void myhandler(int signum) 
{ 
    complete = 1; 
} 

Моя главная функция

int main() 
{ 
    char s[STORAGE]; // array of words 
    char *newargv[MAXITEM]; 
    char inArray[STORAGE]; // for < 
    char outArray[STORAGE]; // for > 
    int firstCheck; 
    int pidBackground; // holds value from fork(), used for background calls 
    struct stat st; // for stat(), checks if file exists 

    // dynamic array based on numPipes 
    // first child doesn't use this array, as it uses newargv[0] and newargv 
    // only the middle children and last child use this array, hence 10 
    int *pipeArray = malloc(10 * sizeof(int)); 

    int numLoops = 0; 
    int i = 0; 

    signal(SIGTERM, myhandler); 

    for(;;) 
    { 
     // Reset flags here 
     lessthanSign = 0; 
     greaterthanSign = 0; 
     pipeSign = 0; 
     firstChildFlag = 0; 
     lastChildFlag = 0; 
     pipeIndex = 0; 


     parse(s, newargv, inArray, outArray, pipeArray); 
     pipeHandler(newargv, inArray, outArray, pipeArray); 
     wait(NULL); 
     fflush(NULL); 

    } // end for 
    printf("Entering killpg; numLoops = %d\n", numLoops); 
    killpg(getpid(), SIGTERM); 
    printf("p2 terminated.\n"); 
    exit(0); 
} // end main 

Основные вызовы разбора, который заполняет newargv []. Он также заполняет inArray [] и outArray [] строкой сразу после < и> соответственно. При обнаружении знака трубы он помещает нуль в newargv [], а также помещает значение в pipeArray [] для индексации имени исполняемого файла в newargv. Я опустил вызовы parse() и flagHandler(), чтобы сохранить их минимальными.

Мои parseHandler() функция

int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray) 
{ 
    pid_t firstChild; 
    pid_t firstChildBackground; 
    pid_t middleChild; 
    pid_t lastChild; 
    pid_t lastChildBackground; 
    int i = 0; // plain integer for for loops 

    printf("Initializing pipes\n"); 
    //pipe(fildes); 
    //pipe(fildes + 2); 
    for (i = 0; i < (2*numPipes); i+=2) 
    { 
     printf("pipe initializing; i is %d\n", i); 
     if (pipe(fildes + i) < 0) 
     { 
      perror("pipe initialization failed"); 
      exit(EXIT_FAILURE); 
     } 
    } 


    fflush(stdout); 
    if ((firstChild = fork()) < 0) 
    { 
     perror("First child's fork failed!"); 
     exit(EXIT_FAILURE); 
    } 
    printf("firstChild pid = %d\n", getpid()); 
    if (firstChild == 0) 
    { 

     if (firstChildFlag == 1) 
     { 
      printf("inFD = open...\n"); 
      inFD = open(inArray, O_RDONLY); 
      printf("Doing dup2 inFD\n"); 
      if (dup2(inFD, STDIN_FILENO) < 0) 
      { 
       perror("First child's < dup2 failed"); 
       exit(EXIT_FAILURE); 
      } 
     } 

     printf("doing dup2 fildes[writeDes]\n"); 
     if (dup2(fildes[writeDes], STDOUT_FILENO) < 0) 
     { 
      perror("First child's dup2 failed"); 
      exit(EXIT_FAILURE); 
     } 
     printf("*****doing dup2 fildes[writeDes] was a success!\n"); 

     for (i = 0; i < 4; i++) 
     { 
      if (close(fildes[i]) < 0) 
      { 
       perror("close failed"); 
       exit(EXIT_FAILURE); 
      } 
     } 
     if (firstChildFlag == 1) 
     { 
      lessthanSign = 0; 
      firstChildFlag = 0; 

      if (close(inFD) < 0) 
      { 
       perror("close inFD failed"); 
       exit(EXIT_FAILURE); 
      } 
     } 

     writeDes += 2; 

     printf("About to execvp first child\n"); 
     if (execvp(ptrArray[0], ptrArray) < 0) 
     { 
      perror("execvp failed"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    else 
    { 
     fflush(stdout); 
     if ((middleChild = fork() < 0)) 
     { 
      perror("Middle child's fork failed"); 
      exit(EXIT_FAILURE); 
     } 
     printf("middleChild pid = %d\n", getpid()); 
     if (middleChild == 0) 
     { 
      if (dup2(fildes[readDes], STDIN_FILENO) < 0) 
      { 
       perror("Middle child's dup2 on reading failed"); 
       exit(EXIT_FAILURE); 
      } 
      if (dup2(fildes[writeDes], STDOUT_FILENO) < 0) 
      { 
       perror("Middle child's dup2 on writing failed"); 
       exit(EXIT_FAILURE); 
      } 

      for (i = 0; i < 4; i++) 
      { 
       if (close(fildes[i]) < 0) 
       { 
        perror("close failed"); 
        exit(EXIT_FAILURE); 
       } 
      } 

      readDes += 2; 
      writeDes += 2; 

      if (execvp(ptrArray[pipeArray[0]], ptrArray + pipeArray[0]) < 0) 
      { 
       perror("Middle child's execvp failed"); 
       exit(EXIT_FAILURE); 
      } 
     } 
     else 
     { 
      fflush(stdout); 
      if ((lastChild = fork() < 0)) 
      { 
       perror("Last child's fork failed"); 
       exit(EXIT_FAILURE); 
      } 
      printf("lastChild pid = %d\n", getpid()); 
      if (lastChild == 0) 
      { 
       if (dup2(fildes[readDes], STDOUT_FILENO) < 0) 
       { 
        perror("Last child's dup2 on reading failed"); 
        exit(EXIT_FAILURE); 
       } 
       if (lastChildFlag == 1) 
       { 
        outFD = open(outArray, O_CREAT | O_RDWR, 0400 | 0200); 
        if (dup2(outFD, STDOUT_FILENO) < 0) 
        { 
         perror("Last child's > dup2 failed"); 
         exit(EXIT_FAILURE); 
        } 
       } 

       for (i = 0; i < 4; i++) 
       { 
        if (close(fildes[i]) < 0) 
        { 
         perror("close failed"); 
         exit(EXIT_FAILURE); 
        } 
       } 
       if (lastChildFlag == 1) 
       { 
        greaterthanSign = 0; 
        lastChildFlag = 0; 
        if (close(outFD) < 0) 
        { 
         perror("close on outFD failed"); 
         exit(EXIT_FAILURE); 
        } 
       } 

       printf("Execvp last child\n"); 
       if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0) 
       { 
        perror("Last child's execvp failed"); 
        exit(EXIT_FAILURE); 
       } 
       printf("Last child execvp finished\n"); 
      } 
     } 
    } 


    // Only the parent gets here 
    printf("Only the parent should be here\n"); 
    printf("My pid is %d\n", getpid()); 
    for (i = 0; i < 4; i++) 
    { 
     if (close(fildes[i]) < 0) 
     { 
      perror("close failed"); 
      exit(EXIT_FAILURE); 
     } 
    } 

    for (;;) 
    { 
     pid_t pid; 
     if (pid = wait(NULL) < 0) 
     { 
      perror("wait failed"); 
      exit(EXIT_FAILURE); 
     } 
     if (pid == lastChild) 
     { 
      printf("Parent is waiting for lastChild\n"); 
      break; 
     } 
    } 

    printf("Parent finished waiting. Returning...\n"); 
    return 0; 
} 

я сделал трубку (Филдс) перед любой вилкой, так что все дети и родителя имеют свою копию. Поэтому я должен закрыть все дескрипторы файлов в каждом дочернем элементе (после dup2, но до execvp) и родителя. Затем родитель будет ждать, пока не получит pid lastChild.

С большим количеством утверждений printf я обнаружил, что ни один из них не выполняет команду dup2() (за исключением dup2 (inFD ...) и dup2 (outFD ...), когда флаги подходят). Также не печатается ошибка.

Я напечатал my (char) newargv [] и my (int) pipeArray [] и содержит правильные значения. Кажется, это всего лишь проблема dup2, и я совершенно не знаю, что с ней происходит.

Я создал простой текстовый файл test2 содержащий ls | сортировать | cat someString Где someString - это просто файл с некоторым текстом. Со всеми операциями печати в функции pipeHandler() мой вывод:

EDIT: Я исправил пару опечаток, которые у меня были. Я забыл зашнуровать дополнительный набор скобок на 3 МФС, если ((FirstChild = вилка() 0 < 0)

теперь у меня есть бесконечный цикл, как родитель ждет ВЗОМТ в LastChild в Вот результат:.

Initializing pipes 
numpipes = 2 
pipe initializing; i is 0 
pipe initializing; i is 2 
firstChild pid = 20521 
firstChild pid = 20522 
doing dup2 fildes[writeDes] 
middleChild pid = 20521 
middleChild pid = 20523 
lastChild pid = 20521 
Only the parent should be here 
My pid is 20521 
lastChild pid = 20524 
<infinite loop> 

Я все еще невежественны, хотя, как к тому, что происходит или что потенциально останавливая ребенка.

+1

Удалите макрос 'CHK' и проверьте возврат самостоятельно. Распечатайте сообщение об ошибке, если вы обнаружите ошибку. Посмотрите, что будет потом. RIght теперь нам не удастся попробовать ваш код, так как у нас нет определения макроса 'CHK'. – davmac

+2

(также исправить отступы и разместить _complete_, но также пример _minimal verifiable_ - основной метод отсутствует. См. [MCVE]). – davmac

+0

Макрос CHK(), вероятно, более чем один раз оценивает его аргументы. – wildplasser

ответ

0

@MarkPlotnick ты прав! Это не то, что dup2 не выполняет или ничего. Потому что я сделал dup2 (fildes [1], STDOUT_FILENO), все распечатки будут переданы по трубопроводам.

Я исправил упоминаемую опечатку. Я попробовал тестовый файл моего учителя < input1 cat |> ваш.outputc tr a-z A-Z | tr \ q Что должно получиться в файле с именем your.outputc. Он делает, и содержимое вводится1 с эффектами tr. Однако у меня также есть инструкции printf в верхней части этого файла.

Я предположил, что dup2 не работал, потому что не было никаких утверждений printf, в отличие от этого в dup2 (inFD, STDIN_FILENO), но это, вероятно, потому, что это был STDIN.