Работа с пайпами (сложное задание)

Тема в разделе "WASM.UNIX", создана пользователем nbyte, 1 окт 2010.

  1. nbyte

    nbyte New Member

    Публикаций:
    0
    Регистрация:
    27 май 2007
    Сообщения:
    161
    Здравствуйте.
    Может тут найдуться люди которые знают хорошо эти вещи и смогут подсказать.
    Мне нужно написать простую shell программу.
    Должна быть реализована возможность работы с конвейерами.
    Тоесть пользователь вводит что-то как в bash через | , а программа должна запустить, показать результат и дождаться когда все завершат работу.
    (только на функции начинающийся со слова parse не смотрите так они очень громоздкие но работают нормально и создаю впечатление запутанного кода)
    (и тройной массив у меня нужен, так как я хочу ещё реализовать запуск программ отделённых & в фоновом режиме)
    У меня получился вот такой вот код
    Код (Text):
    1. //---------------------------------------------------------------------------
    2.  
    3. #pragma hdrstop
    4.  
    5. #include <fcntl.h>
    6. #include <string.h>
    7. #include <stdlib.h>
    8. #include <errno.h>
    9. #include <stdio.h>
    10. #include <netinet/in.h>
    11. #include <resolv.h>
    12. #include <sys/socket.h>
    13. #include <arpa/inet.h>
    14. #include <unistd.h>
    15. #include <sys/types.h>
    16. #include <sys/wait.h>
    17.  
    18. void parseA(char* input);
    19. void parseB(char* input);
    20. void parseC(char* input);
    21. void parseD(char* input);
    22.  
    23.  
    24.  
    25.  
    26.  
    27.  
    28.  
    29. char* cmdparams[20][20][20] = {NULL};
    30. int block = 0;
    31. int cmd = 0;
    32. int param = 0;
    33.  
    34. void parseA(char* input)
    35. {
    36.     while (input[0] != 0)
    37.     {
    38.         cmd = 0;
    39.         const char* delim = strchr(input, '|');
    40.         if (delim)
    41.         {
    42.             int len = delim-input;
    43.             char* subcmd = (char*)malloc(len);
    44.             strncpy(subcmd, input, len);
    45.             subcmd[len] = '\0';
    46.  
    47.             parseB(subcmd);
    48.             block++;
    49.             strcpy(input, delim+1);
    50.         }
    51.         else
    52.         {
    53.             parseB(input);
    54.             return;
    55.         }
    56.     }
    57. }
    58.  
    59. void parseB(char* input)
    60. {
    61.     while (input[0] != 0)
    62.     {
    63.         param = 0;
    64.         char* delim = strchr(input, '&');
    65.         if (delim)
    66.         {
    67.             int len = delim-input;
    68.             char* subcmd = (char*)malloc(len);
    69.             strncpy(subcmd, input, len);
    70.             subcmd[len] = '\0';
    71.             parseC(subcmd);
    72.             cmd++;
    73.             strcpy(input, delim+1);
    74.         }
    75.         else
    76.         {
    77.             parseC(input);
    78.             return;
    79.         }
    80.     }
    81. }
    82.  
    83. void parseC(char* input)
    84. {
    85.    while (input[0] == ' ') strcpy(input, input+1);
    86.    while (input[strlen(input)-1] == ' ') input[strlen(input)-1] = '\0';
    87.  
    88.    while (input[0] != 0)
    89.    {
    90.         char* delim = strchr(input, ' ');
    91.         if (delim)
    92.         {
    93.             int len = delim-input;
    94.             char* subcmd = (char*)malloc(len);
    95.             strncpy(subcmd, input, len);
    96.             subcmd[len] = '\0';
    97.             parseD(subcmd);
    98.             param++;
    99.             strcpy(input, delim+1);
    100.         }
    101.         else
    102.         {
    103.             parseD(input);
    104.             return;
    105.         }
    106.    }
    107.    
    108. }
    109.  
    110. void parseD(char* input)
    111. {
    112.     cmdparams[block][cmd][param] = input;
    113. }
    114. //---------------------------------------------------------------------------
    115.  
    116.  
    117.  
    118.  
    119. //---------------------------------------------------------------------------
    120.  
    121.  
    122.  
    123. int main(int argc, char* argv[])
    124. {
    125.     char input[] = "ls -l | cut -c 1-20 | cut -c 1-1 \0";
    126.     //char input[] = "sleep 1 & sleep 2 \0";
    127.     parseA(input);
    128.     if (input[0] == 0) {perror("no params"); exit(1);}
    129.  
    130.     int i = 0;
    131.     int e = 0;
    132.     int ids[20];
    133.     int pipes[20][2];
    134.     for (int i = 0; i < block; i++)
    135.         pipe(pipes[i]);
    136.  
    137.     while (cmdparams[i][e][0] != NULL)
    138.     {
    139.         while (cmdparams[i][e][0] != NULL)
    140.         {
    141.             if (pipe(pipes[i]) == -1)    {perror("error creating pipe"); exit(1);}
    142.             if (cmdparams[i][e][0] != NULL)
    143.             {
    144.                 if ((ids[i*e] = fork()) == -1)   {perror("error creating child process"); exit(1);}
    145.                 if (ids[i*e] != 0)
    146.                 {
    147.                     if (cmdparams[i-1][e][0] != NULL)
    148.                     {
    149.                         dup2(pipes[i-1][0], 0);
    150.                         close(pipes[i-1][0]);
    151.                         close(pipes[i-1][1]);
    152.                     }
    153.                     if (cmdparams[i+1][e][0] != NULL)
    154.                     {
    155.                         close(pipes[i][0]);
    156.                         dup2(pipes[i][1], 1);
    157.                         close(pipes[i][1]);
    158.                     }
    159.  
    160.                     //printf("%s\n", cmdparams[i][e][0]);
    161.                     execvp(cmdparams[i][e][0], cmdparams[i][e]);
    162.                     printf("%s ", cmdparams[i][e][0]);
    163.                     //perror("error executing child process");
    164.                     exit(1);
    165.                 }
    166.                 else
    167.                 {
    168.                     if (cmdparams[i-1][e][0] != NULL)
    169.                     {
    170.                         close(pipes[i-1][0]);
    171.                         close(pipes[i-1][1]);
    172.                     }
    173.                     if (cmdparams[i+1][e][0] != NULL)
    174.                     {
    175.                          pipes[i-1][0] = pipes[i][0];
    176.                          pipes[i-1][1] = pipes[i][0];
    177.                     }
    178.  
    179.                     dup2(pipes[i][1], 0);
    180.                 }
    181.             }
    182.             e++;
    183.         }
    184.  
    185.         i++;
    186.         e = 0;
    187.     }
    188.  
    189.  
    190.  
    191.     for (int i = 0; i < block*cmd; i++)
    192.     {
    193.         int childExitStatus;
    194.         pid_t ws = waitpid(ids[i*e], &childExitStatus, WNOHANG);
    195.         if( WIFEXITED(childExitStatus) )
    196.         {
    197.             printf("Result of waitpid: Child process exited thus exec failed.");
    198.         }
    199.     }
    200.  
    201.     printf("exited ok\n");
    202.  
    203.  
    204.     //getchar();
    205.     return 0;
    206. }
    207. //---------------------------------------------------------------------------
    Проблема в том что у меня програма не доходит до слова printf("exited ok\n"); но результат выдаёт.
    Вся реализация очень сложна (по крайне мере для меня ) и руководствовался http://stackoverflow.com/questions/916900?tab=newest#tab-top
    Там я чётко не могу выловить код.
     
  2. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    Отлаживайте программу - поставьте точки останова на printf("exited ok\n"); и на ключевые места программы.

    Вот это
    Код (Text):
    1. if ((ids[i*e] = fork()) == -1)   {...}
    2. if (ids[i*e] != 0) {
    3. ...
    4. exit(1);
    5. }
    сравнивает результат fork с нулем. И если это не ноль - то процесс завершает работу. В документации сказано что fork возвращает > 0 родительскому процессу, а дочернему - 0. Думаю, у вас просто завершаются все процессы (и самый первый родительский - тоже) на этом exit(1), поэтому до printf("exited ok\n") дело не доходит.
    Попробуйте первое fork-ветвление сделать без exit(1), например, сохраняя кол-во сделанных ветвлений в счетчике. Если счетчик > 0, сделать exit(1).
     
  3. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    А в man execvp написано следующее:

    The execv() and execvp() functions provide an array of pointers to
    null-terminated strings that represent the argument list available to
    the new program. The first argument, by convention, should point to
    the filename associated with the file being executed. The array of
    pointers must be terminated by a NULL pointer.



    Остальное не разглядывал.
     
  4. nbyte

    nbyte New Member

    Публикаций:
    0
    Регистрация:
    27 май 2007
    Сообщения:
    161
    Не, завершится он у меня не может из-за того что его id всегда равно 0, следовательно на exit(1) он не попадёт.
    А дочернии процессы тоже не должны попадать на exit(1) так это тольок должно случится если указать неправильно параметры execvp

    r90
    А у меня сама функция execvp работает правильно исходя из того что результат сам (с работой двух пайпов) я получаю правильный.
     
  5. nbyte

    nbyte New Member

    Публикаций:
    0
    Регистрация:
    27 май 2007
    Сообщения:
    161
    Ещё раз присмотрел код на свежую голову и понял, что проблема в другом.
    У меня почему-то не происходит корректный возврат в консоль иногда.
     
  6. nbyte

    nbyte New Member

    Публикаций:
    0
    Регистрация:
    27 май 2007
    Сообщения:
    161
    Слушайте можете подсказать что за код такой тут такой http://stackoverflow.com/questions/916900?tab=newest#tab-top
    например

    Как его применить к исходнику что-бы он подправил его? (там-же есть исходик)
     
  7. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    Это для программки под названием patch. Скорми ей, она сделает все правки.
     
  8. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    nbyte, тогда добавляйте отладочную печать в подозрительные места программы и поглядывайте - что не выводится на экран.
    Можно даже выводить на экран саму строчку исходного кода - будет понятно - что выполнилось, а что - нет.
     
  9. nbyte

    nbyte New Member

    Публикаций:
    0
    Регистрация:
    27 май 2007
    Сообщения:
    161
    Вообщем разобрался.
    У меня проблема была с
    Код (Text):
    1. waitpid(ids[i], &childExitStatus, 0);