Понимаю ли я, как файловые дескрипторы Unix работают в C?

Короткая программа ниже предназначена для перебора argv, переданного из командной строки, и выполнения каждого аргумента. Это не моя домашняя работа, это то, что я делаю, готовясь к выполнению своей домашней работы.

Первый аргумент получает входные данные от STDIN и STDOUT и записывает в конвейер. В конце каждой итерации (кроме последней) дескрипторы файлов меняются местами, так что канал, в который записано последнее выполнение, будет прочитан следующим. Таким образом, я намерен, например, для

./a.out /bin/pwd /usr/bin/wc 

распечатать только длину рабочего каталога. Код следует за

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

main(int argc, char * argv[]) {                                                 

  int i;
  int left[2], right[2], nbytes; /* arrays for file descriptors */

  /* pointers for swapping */
  int (* temp);
  int (* leftPipe) = left;                 
  int (* rightPipe) = right;

  pid_t childpid;                                                               
  char readbuffer[80];                                                          

  /* for the first iteration, leftPipe is STDIN */
  leftPipe[0] = STDIN_FILENO;
  leftPipe[1] = STDOUT_FILENO;

  for (i = 1; i < argc; i++) {                                                  

    /* reopen the right pipe (is this necessary?) */
    pipe(rightPipe);                                                            
    fprintf(stderr, "%d: %s\n", i, argv[i]);
    fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);                                                                                    
    if ((childpid = fork()) == -1) {                                            
      perror("fork");                                                           
      exit(1);                                                                  
    }                                                                           

    if (childpid == 0) {                                                        

      /* read input from the left */                                            
      close(leftPipe[1]); /* close output */                                    
      dup2(leftPipe[0], STDIN_FILENO);                                          
      close(leftPipe[0]); /* is this necessary? A tutorial seemed to be doing this */ 

      /* write output to the right */                                           
      close(rightPipe[0]); /* close input */                                    
      dup2(rightPipe[1], STDOUT_FILENO);                                        
      close(rightPipe[1]);                                                      

      execl(argv[i], argv[i], NULL);                                            
      exit(0);                                                                  
    }                                                                           

    wait();                                                                     

    /* on all but the last iteration, swap the pipes */
    if (i + 1 < argc) {              

      /* swap the pipes */                                                      
      fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
      temp = leftPipe;                                                          
      leftPipe = rightPipe;                                                     
      rightPipe = temp;                                                         
      fprintf(stderr, "%d %d %d %d\n", leftPipe[0], leftPipe[1], rightPipe[0], rightPipe[1]);
    }                                                                           
  }                                                                             

    /* read what was last written to the right pipe */                          
    close(rightPipe[1]); /* the receiving process closes 1 */                  

    nbytes = read(rightPipe[0], readbuffer, sizeof(readbuffer));       
    readbuffer[nbytes] = 0;
    fprintf(stderr, "Received string: %s\n", readbuffer);                                

  return 0;                                                                     
}

ОБНОВЛЕНИЕ : во всех нижеприведенных тестовых примерах я изначально использовал / bin / wc, но который показал, что туалет находится совсем не там, где я думал. Я исправляю результаты.

Результат в тривиальном случае (./a.out / bin / pwd) такой, как ожидалось:

1: /bin/pwd
Received string: /home/zeigfreid/Works/programmatical/Langara/spring_2012/OS/labs/lab02/play

Результат выполнения этой программы с первым примером (./a.out / bin / pwd / usr / bin / wc):

1: /bin/pwd
0 1 3 4
3 4 0 1
2: /bin/wc

В этот момент терминал зависает (возможно, ожидает ввода).

Как видите, строка не получена. Я полагаю, что я сделал что-то неправильно выше, либо при замене указателей, либо что я не понимаю дескрипторы файлов unix. Моим заданием, в конце концов, будет интерпретация труб произвольной длины, и это одна из моих идей для решения проблемы.Мне сложно понять, правильно ли я нахожусь на верном пути, чтобы лаять на дерево. Я понимаю файловые дескрипторы unix?

ОБНОВЛЕНИЕ:

Запустив его с / bin / ls в качестве второго аргумента, я получил следующий результат (числа - это дескрипторы файлов в разных точках):

1: /bin/pwd
0 1 3 4
0 1 3 4
3 4 0 1
2: /bin/ls
3 4 5 6
Received string: a.out
log
pipe2.c
play.c
@

В конце все еще есть мусор, но теперь меня больше беспокоит то, что я не понимаю указатели! Однако эти две команды независимы друг от друга, они на самом деле не используют канал.

ОБНОВЛЕНИЕ : символ мусора возник из-за того, что строка не закрывалась. Сейчас закрываю, а фигня нет.

7
задан Bill the Lizard 19 September 2012 в 16:33
поделиться