romko11l

Untitled

Dec 18th, 2019
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 31.79 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/wait.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9. #include <signal.h>
  10.  
  11.  
  12. const int number_of_symbols = 5; // на сколько элементов выделится память (символов) при заполнении строки (read_line) (не делать меньше 3)
  13. const int other_number_of_symbols = 5; // на сколько элементов (символов) выделится память в функции strtok
  14. const int number_of_strings = 5; // на сколько строк выделится память в функции parcer
  15.  
  16.  
  17. /*
  18.   @function      freedom() - очищает память, занятую массивом строк
  19.   @param         char **base - массив строк, заканчивающийся NULL-ссылкой
  20. */
  21. void freedom (char **base)
  22. {
  23.     int pos=0;
  24.     while (base[pos])
  25.     {
  26.         free(base[pos]);
  27.         pos++;
  28.     }
  29.     free(base);
  30. }
  31.  
  32.  
  33. /*
  34.   @function      sighndlr() - печать предупреждения
  35.   Обрабатывает сигнал SIGUSR1, который посылает сыновний процесс (в случае ошибки execc), у которого закрыт стандартный вывод, отцу - процессу, формирующему конвейер
  36. */
  37. void sighndlr ()
  38. {
  39.     printf("Не удалось запустить программу\n");
  40. }
  41.  
  42. /*
  43.   @function      char *readline() - читает одну строку из заданного ввода
  44.   @param         int fd - дескриптор заданного ввода
  45.   @param         int *check - в этом параметре вернём 1, если в строке обнаружен EOF, иначе 0
  46.   @return        возвращает прочитанную строку
  47. */
  48. char *read_line(int file_descriptor, int *check)
  49. {
  50.     int position=0, size;
  51.     char *str, *temp, symbol, read_items;
  52.     size=number_of_symbols;
  53.     str=malloc(sizeof(char)*size);
  54.     *check=0;
  55.    
  56.     if (!str)
  57.     {
  58.         printf("memory allocation error\n");
  59.         exit(1);
  60.     }
  61.    
  62.     while (1)
  63.     {
  64.         read_items=read(file_descriptor,&symbol,sizeof(char));
  65.         if ((read_items==0)||(symbol=='\n'))
  66.         {
  67.             str[position]='\0';
  68.             if (read_items==0)
  69.             {
  70.                 *check=1;
  71.             }
  72.             return str;
  73.         }
  74.         else
  75.         {
  76.             str[position]=symbol;
  77.             position++;
  78.         }
  79.    
  80.         if (position==size)
  81.         {
  82.             size=size+number_of_symbols;
  83.             temp=str;
  84.             str=realloc(str,size*sizeof(char));
  85.             if (!str)
  86.             {
  87.                 free(temp);
  88.                 printf("memory allocation error\n");
  89.                 exit(1);
  90.             }
  91.         }
  92.     }
  93.    
  94. }
  95.  
  96.  
  97. /*
  98.   @function      char *mystrtok() - вычленяет лексему из строки
  99.   @param         char *line - строка, из которой вычленяется лексема
  100.   @param         int *check - в этом параметре вернём 1, если данная лексема - последняя перед концом строки, 2 - если произошла ошибка выделения памяти, иначе 0
  101.   @param         int *num - в этом параметре возвращаем позицию последнего символа, который записан в вычлененную лексему
  102.   @return        возвращает в виде полноценной строки первую лексему, которую возможно вычленить
  103. */
  104. char *mystrtok (char *line, int *check, int *num)
  105. {
  106.     int size, pos=0, hpos=0, pos1, hpos1;
  107.     // pos - позиция в основной строке
  108.     // hpos - (вспомогательная) позиция в формируемой строке
  109.     // pos1, hpos1 - нужны для обработки кавычек
  110.     char *str, *temp;
  111.     size=other_number_of_symbols;
  112.     str=malloc(sizeof(char)*size);
  113.     if (!str)
  114.     {
  115.         printf("memory allocation error\n");
  116.         *check=2;
  117.         free(str);
  118.         return NULL;
  119.     }
  120.    
  121.     while (1)
  122.     {
  123.         // Обработка кавычек
  124.         if (line[pos]=='"')
  125.         {
  126.             pos1=pos+1;
  127.             hpos1=hpos;
  128.             while (1)
  129.             {
  130.                 if (line[pos1]=='"')
  131.                 {
  132.                     hpos=hpos1;
  133.                     pos=pos1+1;
  134.                     break;
  135.                 }
  136.                 if ((line[pos1]==EOF)||(line[pos1]=='\0'))
  137.                 {
  138.                     break; // не найдено парной кавычки -> кавычка должна считаться как обычный символ
  139.                 }
  140.                 str[hpos1]=line[pos1];
  141.                 hpos1++;
  142.                 pos1++;
  143.                 if (hpos1==size)
  144.                 {
  145.                     temp=str;
  146.                     size=size+other_number_of_symbols;
  147.                     str=realloc(str,size*sizeof(char));
  148.                     if (!str)
  149.                     {
  150.                         free(temp);
  151.                         printf("memory allocation error\n");
  152.                         *check=2;
  153.                         return NULL;
  154.                     }
  155.                 }
  156.             }
  157.         }
  158.         // Обработка иных случаев
  159.         if (line[pos]==' ')
  160.         {
  161.             if (hpos==0)
  162.             {
  163.                 pos++;
  164.             }
  165.             else
  166.             {
  167.                 str[hpos]='\0';
  168.                 *check=0;
  169.                 *num=pos; // чтобы в следующий раз отправить в эту функцию другую строку
  170.                 return str;
  171.                
  172.             }
  173.         }
  174.         else
  175.         {
  176.             if (line[pos]=='\0')
  177.             {
  178.                 if (hpos==0)
  179.                 {
  180.                     *check=1;
  181.                     free(str);
  182.                     return NULL;
  183.                 }
  184.                 else
  185.                 {
  186.                     str[hpos]='\0';
  187.                     *check=1;
  188.                     return str;
  189.                 }
  190.             }
  191.             else // обнаружен элемент, который можно записать в строку
  192.             {
  193.                 // Обрабатываем спецсимволы
  194.                 if ((line[pos]=='|')||(line[pos]=='&')||(line[pos]=='>')||(line[pos]=='<')||(line[pos]==';')||(line[pos]==')')||(line[pos]=='('))
  195.                 {
  196.                     if (hpos>0) //до этого уже сформирована строка
  197.                     {
  198.                         str[hpos]='\0';
  199.                         *check=0;
  200.                         *num=pos;
  201.                         return str;
  202.                     }
  203.                     else // строка еще не сформирована (hpos==0)
  204.                     {
  205.                         // |
  206.                         if (line[pos]=='|')
  207.                         {
  208.                             if (line[pos+1]=='|')
  209.                             {
  210.                                 str[0]='|';
  211.                                 str[1]='|';
  212.                                 str[2]='\0';
  213.                                 *check=0;
  214.                                 *num=pos+2;
  215.                                 return str;
  216.                             }
  217.                             else
  218.                             {
  219.                                 str[0]='|';
  220.                                 str[1]='\0';
  221.                                 *check=0;
  222.                                 *num=pos+1;
  223.                                 return str;
  224.                             }
  225.                         }
  226.                         // &
  227.                         if (line[pos]=='&')
  228.                         {
  229.                             if (line[pos+1]=='&')
  230.                             {
  231.                                 str[0]='&';
  232.                                 str[1]='&';
  233.                                 str[2]='\0';
  234.                                 *check=0;
  235.                                 *num=pos+2;
  236.                                 return str;
  237.                             }
  238.                             else
  239.                             {
  240.                                 str[0]='&';
  241.                                 str[1]='\0';
  242.                                 *check=0;
  243.                                 *num=pos+1;
  244.                                 return str;
  245.                             }
  246.                         }
  247.                         // >
  248.                         if (line[pos]=='>')
  249.                         {
  250.                             if (line[pos+1]=='>')
  251.                             {
  252.                                 str[0]='>';
  253.                                 str[1]='>';
  254.                                 str[2]='\0';
  255.                                 *check=0;
  256.                                 *num=pos+2;
  257.                                 return str;
  258.                             }
  259.                             else
  260.                             {
  261.                                 str[0]='>';
  262.                                 str[1]='\0';
  263.                                 *check=0;
  264.                                 *num=pos+1;
  265.                                 return str;
  266.                             }
  267.                         }
  268.                         // <
  269.                         if (line[pos]=='<')
  270.                         {
  271.                             str[0]='<';
  272.                             str[1]='\0';
  273.                             *check=0;
  274.                             *num=pos+1;
  275.                             return str;
  276.                         }
  277.                         // ;
  278.                         if (line[pos]==';')
  279.                         {
  280.                             str[0]=';';
  281.                             str[1]='\0';
  282.                             *check=0;
  283.                             *num=pos+1;
  284.                             return str;
  285.                         }
  286.                         // )
  287.                         if (line[pos]==')')
  288.                         {
  289.                             str[0]=')';
  290.                             str[1]='\0';
  291.                             *check=0;
  292.                             *num=pos+1;
  293.                             return str;
  294.                         }
  295.                         // (
  296.                         if (line[pos]=='(')
  297.                         {
  298.                             str[0]='(';
  299.                             str[1]='\0';
  300.                             *check=0;
  301.                             *num=pos+1;
  302.                             return str;
  303.                         }
  304.                     }
  305.                 }
  306.                 //Если встречен обычный символ
  307.                 str[hpos]=line[pos];
  308.                 hpos++;
  309.                 pos++;
  310.                 if (hpos==size)
  311.                 {
  312.                     temp=str;
  313.                     size=size+other_number_of_symbols;
  314.                     str=realloc(str,size*sizeof(char));
  315.                     if (!str)
  316.                     {
  317.                         free(temp);
  318.                         printf("memory allocation error\n");
  319.                         *check=2;
  320.                         return NULL;
  321.                     }
  322.                 }
  323.             }
  324.         }
  325.        
  326.     }
  327. }
  328.  
  329.  
  330. /*
  331.   @function      char **divide_to_lexemes() - разбивает строку на лексемы
  332.   @param         char *line - строка, из которой вычленяются лексемы
  333.   @return        возвращает массив строк (оканчивающийся NULL-ссылкой), сформированный из вычлененных лексем
  334. */
  335. char **divide_to_lexemes (char *line)
  336. {
  337.     int check, pos=0, size=0, strpos=0, hstrpos=0;
  338.     // strpos - сдвиг строки (все, что до этого сдвига уже поделено не лексемы)
  339.     // hstrpos - на что увеличится strpos после вычленения очередной лексемы
  340.     char **base, **temp;
  341.     size=number_of_strings;
  342.     base=malloc(sizeof(char *)*size);
  343.     if (!base)
  344.     {
  345.         printf("memory allocation error\n");
  346.         free(line);
  347.         exit(1);
  348.     }  
  349.    
  350.     while(1)
  351.     {
  352.         base[pos]=mystrtok(line+strpos, &check, &hstrpos);
  353.         if (check==2)
  354.         {
  355.             base[pos]=NULL;
  356.             freedom(base);
  357.             exit(1);
  358.         }
  359.        
  360.         if (check==1)
  361.         {
  362.             if (!base[pos]) // вернулась NULL - парсинг строки завершен
  363.             {
  364.                 return base; //может быть даже такое, что первый элемент этого массива - NULL
  365.             }
  366.             else // вернулась не пустая строка, но обнаружен конец основной строки
  367.             {
  368.                 pos++;
  369.                 if (pos==size)
  370.                 {
  371.                     size=size+1;
  372.                     temp=base;
  373.                     base=realloc(base,size*sizeof(char *));
  374.                     if (!base)
  375.                     {
  376.                         free(temp[pos-1]); // т.к. на новый pos места уже нет
  377.                         temp[pos-1]=NULL;
  378.                         freedom(base);
  379.                         exit(1);
  380.                     }
  381.                 }
  382.                 base[pos]=NULL;
  383.                 return base;
  384.             }
  385.         }
  386.        
  387.         if (check==0)
  388.         {
  389.             strpos+=hstrpos;
  390.             pos++;
  391.             if (pos==size)
  392.             {
  393.                 size=size+number_of_strings;
  394.                 temp=base;
  395.                 base=realloc(base,size*sizeof(char *));
  396.                 if (!base)
  397.                 {
  398.                     free(temp[pos-1]); // т.к. на новый pos места уже нет
  399.                     temp[pos-1]=NULL;
  400.                     freedom(base);
  401.                     exit(1);
  402.                 }
  403.             }
  404.         }
  405.     }
  406. }
  407.  
  408. /*
  409.   @function      int cd() - разбивает строку на лексемы
  410.   @param         char *str - строка-аргумент команды cd
  411.   @return        возвращает 0, в случае успешой смены директории, иначе -1
  412. */
  413. int cd (char *str) // проверка на корректность количества аргументов команды cd производится раньше
  414. {
  415.     int res;
  416.     if (str==NULL) //значит пользователю надо перейти в домашний каталог
  417.     {
  418.         res=chdir(getenv("HOME"));
  419.         if (res==-1)
  420.         {
  421.             printf ("В указанный каталог перейти не удалось\n");
  422.         }
  423.         return res;
  424.     }
  425.     else
  426.     {
  427.         res=chdir(str);
  428.         if (res==-1)
  429.         {
  430.             printf ("В указанный каталог перейти не удалось\n");
  431.         }
  432.         return res;
  433.     }
  434. }
  435.  
  436. /*
  437.   @function      int funcion_call() - вызов нового процесса
  438.   @param         char **base - массив строк, первым элементом которого является имя исполняемого файла (полный путь до него) и аргументы командной строки
  439.   @param         int fd[2] - fd[1] дескриптор смены стандартного вывода
  440.   @param         int flag - flag==1 говорит о том, что подан последний процесс из конвейера
  441.   @param         int *key - через этот параметр передаем pid запущенного процесса
  442.   @return        возвращает -1 в случае неудачного fork, -2  в случае неудачного exec, -3 в случае пустой команды, иначе - 0
  443. */
  444. int function_call (char **base, int file_descriptor[2], int flag, int *key)
  445. {  
  446.     int fork_res, exec_res; // проверка различных возвратов
  447.     if (base[0]==NULL)
  448.     {
  449.         dup2(file_descriptor[0],0);
  450.         close(file_descriptor[0]);
  451.         close(file_descriptor[1]);
  452.         return -3;
  453.     }
  454.     fork_res=fork();
  455.     if (fork_res==-1)
  456.     {
  457.         printf("Не удалось породить процесс\n");
  458.         *key=-1;
  459.         return (-1);
  460.     }
  461.     if (fork_res>0)
  462.     {
  463.         dup2(file_descriptor[0],0);
  464.         close(file_descriptor[0]);
  465.         close(file_descriptor[1]);
  466.         *key=fork_res;
  467.     }
  468.     else
  469.     {
  470.         if (flag!=1)
  471.         {
  472.             dup2(file_descriptor[1],1);
  473.         }
  474.         close(file_descriptor[1]);
  475.         close(file_descriptor[0]);
  476.         exec_res=execvp(base[0],base);
  477.         if (exec_res==-1)
  478.         {
  479.             //printf("Не удалось запустить программу - %s\n",base[0]);
  480.             kill(getppid(),SIGUSR1);
  481.             return -2;
  482.         }
  483.     }
  484.     return 0;
  485. }
  486.  
  487.  
  488. /*
  489.   @function      all_str_output() - вывод хранящихся в base строк
  490.   @param         char **base - массив строк, заканчивающийся NULL-ссылкой
  491. */
  492. void all_str_output (char **base)
  493. {
  494.     int pos=0;
  495.     while ((base[pos]))
  496.     {
  497.         printf("%s\n",base[pos]);
  498.         pos++;
  499.     }
  500. }
  501.  
  502.  
  503. /*
  504.   @function      int pipeline() - функция создания конвейера
  505.   @param         char **base - массив строк, из которого вычленяются подмассивы, содержащие имена отдельных процессов
  506.   @param         int bcheck - bcheck==1 говорит о том, что конвейер запускается в фоновом режиме (не нужно восстанавливать реакцию на SIGINT)
  507.   @param         int *transit - неименованный канал, ведущий к logic и использующийся для передачи возвращённого значения запущенного процесса
  508.   @return        возвращает -2 в случае каких-либо ошибок (а также возвращении в теле сыновнего процесса), либо 0 в случае корректной работы
  509. */
  510. int pipeline (char** base, int bcheck, int *transit)
  511. {  
  512.     int len=0, i=0, j=0, fd[2], fork_res, pipe_res, call_res, writeintransit=1, key;
  513.     char **lastinstr, *str;
  514.     if ((base[0]!=NULL)&&(strcmp(base[0],"cd")==0))
  515.     {
  516.         if ((base[1]!=NULL)&&(base[2]!=NULL)) //ошибки не случится, т.к. при false в первом условии проверки второго не осуществиться
  517.         {
  518.             printf("cd: Некорректное число аргументов\n");
  519.             writeintransit=1;
  520.             write(transit[1], &writeintransit, sizeof(int));
  521.         }
  522.         else
  523.         {
  524.             writeintransit=cd(base[1]);
  525.             write(transit[1], &writeintransit, sizeof(int));
  526.         }
  527.         return 0;
  528.     }
  529.     fork_res=fork();
  530.     if (fork_res==-1)
  531.     {
  532.         printf("Породить процесс не удалось\n");
  533.         writeintransit=1;
  534.         write(transit[1], &writeintransit, sizeof(int));
  535.         return -1;
  536.     }
  537.     if (fork_res==0)
  538.     {
  539.         if (bcheck!=1)
  540.         {
  541.             signal(SIGINT,SIG_DFL);
  542.         }
  543.         lastinstr=base;
  544.         while (base[i])
  545.         {
  546.             if (strcmp(base[i],"|")==0)
  547.             {
  548.                 len++;
  549.             }
  550.             i++;
  551.         }
  552.         j=0;
  553.         i=0;
  554.         while (i<len)
  555.         {
  556.             while (strcmp(base[j],"|")!=0)
  557.             {
  558.                 j++;
  559.             }
  560.            
  561.             i++;
  562.             j++;
  563.             pipe_res=pipe(fd);
  564.             if (pipe_res==-1)
  565.             {
  566.                 printf("Не удалось установить связь между процессами конвейера\n");
  567.                 writeintransit=1; // т.к. конвейер построился некорректно
  568.                 write(transit[1], &writeintransit, sizeof(int));
  569.                 return -2;
  570.                 // тут еще надо подумать
  571.             }
  572.            
  573.             str=base[j-1];
  574.             base[j-1]=NULL;
  575.             call_res=function_call(lastinstr, fd, 0, &key);
  576.             base[j-1]=str;
  577.             lastinstr=base+j;
  578.             if (call_res==-2) // возврат в теле сыновнего процесса
  579.             {
  580.                 return -2;
  581.             }
  582.            
  583.             if (call_res==-1)
  584.             {
  585.                 while(wait(NULL)!=-1);
  586.                 writeintransit=1; // т.к. конвейер построился некорректно
  587.                 write(transit[1], &writeintransit, sizeof(int));
  588.                 return -2;
  589.             }
  590.             // call_res = 0 - всё хорошо
  591.         }
  592.        
  593.         // на момент выхода из цикла не вызвана последняя программа из конвейера
  594.         pipe_res=pipe(fd);
  595.         if (pipe_res==-1)
  596.         {
  597.             printf("Не удалось установить связь между процессами конвейера\n");
  598.             writeintransit=1; // т.к. конвейер построился некорректно
  599.             write(transit[1], &writeintransit, sizeof(int));
  600.             return -2;
  601.         }
  602.         call_res=function_call(lastinstr, fd, 1, &key);
  603.         if (call_res==-3) // последняя команда - пустая
  604.         {
  605.             writeintransit=1;
  606.             write(transit[1], &writeintransit, sizeof(int));
  607.             while(wait(NULL)!=-1);
  608.             return -2;
  609.         }
  610.        
  611.         if (call_res==-2) // возврат в теле сыновнего процесса
  612.         {
  613.             return -2;
  614.         }
  615.        
  616.         waitpid(key, &writeintransit, 0);
  617.         write(transit[1], &writeintransit, sizeof(int));
  618.         while(wait(NULL)!=-1);
  619.         return -2;
  620.     }
  621.     // тут может оказаться только процесс-родитель
  622.     wait(NULL);
  623.     return 0;
  624. }
  625.  
  626. /*
  627.   @function      int redirection() - функция обработки перенаправлений
  628.   @param         char **base - массив строк, из которого вычленяется информация о перенаправлениях
  629.   @param         int bcheck - просто передаём дальше в pipeline()
  630.   @param         int *transit - передаём дальше в pipeline()
  631.   @return        возвращает число, которое вернула pipeline()
  632.   Согласно нашему синтаксису требуется, чтобы перенаправления стояли последними 2/4 строками массива
  633. */
  634. int redirection (char **base, int bcheck, int *transit)
  635. {  
  636.     int len=0,fdrd,fdwr,hfd1,hfd2,checkrd=0,checkwr=0,res=0;
  637.     // fdrd - дескриптор на запись
  638.     // fdwr - дескриптор на чтение
  639.     // checkwr==1 - имеется перенаправление вывода
  640.     // checkrd==1 - имеется перенаправление ввода
  641.     // в hfd1, hfd2 заносим стандартные потоки вывода/ввода
  642.     char *str;
  643.     while (base[len]) // кол-во переданных слов
  644.     {
  645.         len++;
  646.     }
  647.     hfd1=dup(1);
  648.     hfd2=dup(0);
  649.     if ((len>=4)&&(strcmp(base[len-2],">>")==0)&&(strcmp(base[len-4],">")==0)&&(strcmp(base[len-3],base[len-1])==0))
  650.     {
  651.         fdwr=open(base[len-1], O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0666);
  652.         if (fdwr==-1)
  653.         {
  654.             fdwr=open(base[len-1], O_TRUNC | O_WRONLY); // возможно, файл уже существует
  655.             if (fdwr==-1)
  656.             {
  657.                 printf("Перенаправление вывода организовать не удалось\n");
  658.                 goto jmp;
  659.             }
  660.         }
  661.         checkwr=1;
  662.         dup2(fdwr,1);
  663.         str=base[len-4];
  664.         base[len-4]=NULL;
  665.         res=pipeline(base,bcheck,transit);
  666.         base[len-4]=str;
  667.         goto jmp;
  668.     }
  669.     if ((len>=4)&&(strcmp(base[len-2],">>")==0)&&(strcmp(base[len-4],"<")==0)&&(strcmp(base[len-3],base[len-1])==0))
  670.     {
  671.         printf("Недопустимая конструкция (входной и выходной файлы совпадают)\n");
  672.         goto jmp;
  673.     }
  674.     if ((len>=4)&&(strcmp(base[len-2],">")==0)&&(strcmp(base[len-4],"<")==0)&&(strcmp(base[len-3],base[len-1])==0))
  675.     {
  676.         printf("Недопустимая конструкция (входной и выходной файлы совпадают)\n");
  677.         goto jmp;
  678.     }
  679.     if ((len>=4)&&(strcmp(base[len-2],"<")==0)&&(strcmp(base[len-4],">")==0)&&(strcmp(base[len-3],base[len-1])==0))
  680.     {
  681.         printf("Недопустимая конструкция (входной и выходной файлы совпадают)\n");
  682.         goto jmp;
  683.     }
  684.     if ((len>=4)&&(strcmp(base[len-2],"<")==0)&&(strcmp(base[len-4],">>")==0)&&(strcmp(base[len-3],base[len-1])==0))
  685.     {
  686.         printf("Недопустимая конструкция (входной и выходной файлы совпадают)\n");
  687.         goto jmp;
  688.     }
  689.     if (len>=2) // потому что ситуация подачи на ввод, например >> text - корректна
  690.     {
  691.         if (strcmp(base[len-2],">")==0)
  692.         {
  693.             fdwr=open(base[len-1], O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0666);
  694.             if (fdwr==-1)
  695.             {
  696.                 fdwr=open(base[len-1], O_TRUNC | O_WRONLY); // возможно, файл уже существует
  697.                 if (fdwr==-1)
  698.                 {
  699.                     printf("Перенаправление вывода организовать не удалось\n");
  700.                     goto jmp;
  701.                 }
  702.             }
  703.             checkwr=1;
  704.             dup2(fdwr,1);
  705.         }
  706.         if (strcmp(base[len-2],">>")==0)
  707.         {
  708.             fdwr=open(base[len-1], O_CREAT | O_APPEND | O_WRONLY | O_EXCL, 0666);
  709.             if (fdwr==-1)
  710.             {
  711.                 fdwr=open(base[len-1], O_APPEND| O_WRONLY);
  712.                 if (fdwr==-1)
  713.                 {
  714.                     printf("Перенаправление вывода организовать не удалось\n");
  715.                     goto jmp;
  716.                 }
  717.             }
  718.             checkwr=1;
  719.             dup2(fdwr,1);
  720.         }
  721.         if (strcmp(base[len-2],"<")==0)
  722.         {
  723.             fdrd=open(base[len-1], O_RDONLY);
  724.             if (fdrd==-1)
  725.             {
  726.                 printf("Перенаправление ввода организовать не удалось\n");
  727.                 goto jmp;
  728.             }
  729.             checkrd=1;
  730.             dup2(fdrd,0);
  731.         }
  732.         if (len>=4)
  733.         {
  734.             if ((checkrd==1)||(checkwr==1))
  735.             {
  736.                 if ((checkrd==1)&&(strcmp(base[len-4],">")==0))
  737.                 {
  738.                     fdwr=open(base[len-3], O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0666);
  739.                     if (fdwr==-1)
  740.                     {
  741.                         fdwr=open(base[len-3], O_TRUNC | O_WRONLY);
  742.                         if (fdwr==-1)
  743.                         {
  744.                             printf("Перенаправление вывода организовать не удалось\n");
  745.                             goto jmp;
  746.                         }
  747.                     }
  748.                     checkwr=1;
  749.                     dup2(fdwr,1);
  750.                 }
  751.                 if ((checkrd==1)&&(strcmp(base[len-4],">>")==0))
  752.                 {
  753.                     fdwr=open(base[len-3], O_CREAT | O_APPEND | O_WRONLY | O_EXCL, 0666);
  754.                     if (fdwr==-1)
  755.                     {
  756.                         fdwr=open(base[len-3], O_APPEND| O_WRONLY);
  757.                         if (fdwr==-1)
  758.                         {
  759.                             printf("Перенаправление вывода организовать не удалось\n");
  760.                             goto jmp;
  761.                         }
  762.                     }
  763.                     checkwr=1;
  764.                     dup2(fdwr,1);
  765.                 }
  766.                 if ((checkwr==1)&&(strcmp(base[len-4],"<")==0))
  767.                 {
  768.                     fdrd=open(base[len-3], O_RDONLY);
  769.                     if (fdrd==-1)
  770.                     {
  771.                         printf("Перенаправление ввода организовать не удалось\n");
  772.                         goto jmp;
  773.                     }
  774.                     checkrd=1;
  775.                     dup2(fdrd,0);
  776.                 }
  777.                 if ((checkwr==1)&&(checkrd==1))
  778.                 {
  779.                     str=base[len-4];
  780.                     base[len-4]=NULL;
  781.                     res=pipeline(base,bcheck,transit);
  782.                     base[len-4]=str;
  783.                 }
  784.                 else
  785.                 {
  786.                     str=base[len-2];
  787.                     base[len-2]=NULL;
  788.                     res=pipeline(base,bcheck,transit);
  789.                     base[len-2]=str;
  790.                 }
  791.             }
  792.             else
  793.             {
  794.                 res=pipeline(base,bcheck,transit);
  795.             }
  796.         }
  797.         else // меньше 4 слов в команде
  798.         {
  799.             if ((checkrd==1)||(checkwr==1)) // только одно из перенаправлений имело место
  800.             {
  801.                 str=base[len-2];
  802.                 base[len-2]=NULL;
  803.                 res=pipeline(base,bcheck,transit);
  804.                 base[len-2]=str;
  805.             }
  806.             else // перенаправлений не было
  807.             {
  808.                 res=pipeline(base,bcheck,transit);
  809.             }
  810.         }
  811.     }
  812.     else // меньше 2 слов в команде
  813.     {
  814.         res=pipeline(base,bcheck,transit);
  815.     }
  816.     jmp:
  817.     if (checkwr==1)
  818.     {
  819.         dup2(hfd1,1);;
  820.         close(fdwr);
  821.     }
  822.     if (checkrd==1)
  823.     {
  824.         dup2(hfd2,0);
  825.         close(fdrd);
  826.     }
  827.     close(hfd1);
  828.     close(hfd2);
  829.     return res;
  830. }
  831.  
  832. /*
  833.   @function      int logic() - функция обработка логики (&&, ||)
  834.   @param         char **base - массив строк, из которого вычленяется информация о логике
  835.   @param         int bcheck - передаем дальше в redirection()
  836.   @return        возвращает -2 в случае каких-либо ошибок, либо 0 в случае корректной работы
  837. */
  838. int logic(char **base, int bcheck)
  839. {
  840.     int lastexit=0; // тут хранится код возврата последнего выполнившегося процесса (и cd)
  841.     int transit[2]; // проведенный до pipeline канал
  842.     int i=0, redirection_res;
  843.     char str1[3]="||", str2[3]="&&", **lastcom, *temp;
  844.     char *lastlogic; //в комбинации с lastexit всегда должна дать выполниться первой команде
  845.     lastlogic=str2;
  846.     while (base[i]!=NULL)
  847.     {
  848.         if ((strcmp(base[i],str1)==0)||(strcmp(base[i],str2)==0))
  849.         {
  850.             if  (i==0)
  851.             {
  852.                 printf("Некорректный синтаксис\n");
  853.                 return 0;
  854.             }
  855.             if ((i>0)&&(strcmp(base[i-1],str1)==0))
  856.             {
  857.                 printf("Некорректный синтаксис\n");
  858.                 return 0;
  859.             }
  860.             if ((i>0)&&(strcmp(base[i-1],str2)==0))
  861.             {
  862.                 printf("Некорректный синтаксис\n");
  863.                 return 0;
  864.             }
  865.         }
  866.         i++;
  867.     }
  868.     if ((i>0)&&((strcmp(base[i-1],"&&")==0)||(strcmp(base[i-1],"||")==0))) // последняя лексема - &&, либо ||
  869.     {
  870.         printf("Некорректный синтаксис\n");
  871.         return 0;
  872.     }
  873.    
  874.     i=0;
  875.     if (pipe(transit)==-1)
  876.     {
  877.         printf("Не удается получить результат процесса\n");
  878.         return -2;
  879.     }
  880.    
  881.     lastcom=base;
  882.     while (base[i]!=NULL)
  883.     {
  884.         if (strcmp(base[i],str1)==0)
  885.         {
  886.             if (((lastexit==0)&&(strcmp(lastlogic,str2)==0))||((lastexit!=0)&&(strcmp(lastlogic,str1)==0)))
  887.             {
  888.                 temp=base[i]; // очень важно делать именно так (иначе портится память)
  889.                 base[i]=NULL;
  890.                 redirection_res=redirection(lastcom,bcheck,transit);
  891.                 base[i]=temp;
  892.                 if (redirection_res!=0) // возврат в случае ошибки fork , либо в теле сыновнего процесса
  893.                 {
  894.                     return -2;
  895.                 }
  896.                 read(transit[0],&lastexit,sizeof(int)); // читаем, что сюда записалось в pipeline
  897.             }
  898.             lastcom=base+i+1;
  899.             lastlogic=str1;
  900.         }
  901.         if (strcmp(base[i],str2)==0)
  902.         {
  903.             if (((lastexit==0)&&(strcmp(lastlogic,str2)==0))||((lastexit!=0)&&(strcmp(lastlogic,str1)==0)))
  904.             {
  905.                 temp=base[i];
  906.                 base[i]=NULL;
  907.                 redirection_res=redirection(lastcom,bcheck,transit);
  908.                 base[i]=temp;
  909.                 if (redirection_res!=0) // возврат в случае ошибки fork , либо в теле сыновнего процесса
  910.                 {
  911.                     close(transit[0]);
  912.                     close(transit[1]);
  913.                     return -2;
  914.                 }
  915.                 read(transit[0],&lastexit,sizeof(int)); // читаем, что сюда записалось в pipeline
  916.             }
  917.             lastcom=base+i+1;
  918.             lastlogic=str2;
  919.         }
  920.         i++;
  921.     }
  922.     // на данный момент не обработана последняя команда
  923.     if (((lastexit==0)&&(strcmp(lastlogic,str2)==0))||((lastexit!=0)&&(strcmp(lastlogic,str1)==0)))
  924.     {
  925.         redirection_res=redirection(lastcom,bcheck,transit);
  926.         if (redirection_res!=0) // возврат в случае ошибки fork , либо в теле сыновнего процесса
  927.         {
  928.             close(transit[0]);
  929.             close(transit[1]);
  930.             return -2;
  931.         }
  932.     }
  933.     close(transit[0]);
  934.     close(transit[1]);
  935.     return 0;
  936. }
  937.  
  938.  
  939. /*
  940.   @function      int backgroud() - функция обработки фонового режима (&) и ;
  941.   @param         char **base - массив строк, из которого вычленяется информация о последовательноти запуска процессов и фоновости режима
  942.   @return        возвращает -2 в случае каких-либо ошибок (а также возвращении в теле сыновнего процесса), либо 0 в случае корректной работы
  943. */
  944. int background (char **base)
  945. {
  946.     char **lastcom, *temp;
  947.     int i=0, res, file_descriptor[2]; // res - осуществляет проверку различных возвратов, по file_descriptor сообщим сыновнему процессу pid отца, чтобы он мог подождать завершения отца
  948.     lastcom=base;
  949.     // проверка на корректность расстановки ; (она не может быть первым символом и стоять рядом с другой ;)
  950.     if ((base[i]!=NULL)&&(strcmp(base[i],";")==0))
  951.     {
  952.         printf("Некорректный синтаксис\n");
  953.         return 0;
  954.     }
  955.    
  956.     while (base[i]!=NULL)
  957.     {
  958.         if (strcmp(base[i],";")==0)
  959.         {
  960.             if ((i>0)&&(strcmp(base[i-1],";")==0))
  961.             {
  962.                 printf("Некорректный синтаксис\n");
  963.                 return 0;
  964.             }
  965.         }
  966.         i++;
  967.     }
  968.    
  969.     i=0;
  970.     jmp:
  971.     while ((base[i]!=NULL)&&(strcmp(base[i],"&")!=0)&&(strcmp(base[i],";")!=0)) // сравнения должны быть именно в таком порядке, иначе в случае strcmp(NULL,...) произойдет страшное
  972.     {
  973.         i++;
  974.     }
  975.    
  976.     if ((base[i]!=NULL)&&(strcmp(base[i],"&")==0))
  977.     {
  978.         res=fork();
  979.         if (res==-1)
  980.         {
  981.             printf("Не удалось породить процесс\n");
  982.             return -2;
  983.         }
  984.         if (res==0)
  985.         {
  986.             pipe(file_descriptor);
  987.             res=fork();
  988.             if (res==-1)
  989.             {
  990.                 printf("Не удалось породить процесс\n");
  991.                 return -2;
  992.             }
  993.             if (res==0)
  994.             {
  995.                 read(file_descriptor[0],&res,sizeof(int));
  996.                 close(file_descriptor[0]);
  997.                 close(file_descriptor[1]);
  998.                 while(getppid()==res)
  999.                 {
  1000.                 }
  1001.                 temp=base[i];
  1002.                 base[i]=NULL;
  1003.                 res=open("/dev/null", O_WRONLY);
  1004.                 dup2(res,0);
  1005.                 logic(lastcom,1);
  1006.                 close(res);
  1007.                 base[i]=temp;
  1008.                 return -2;
  1009.             }
  1010.             // сюда может попасть только процесс-отец
  1011.             res=getpid();
  1012.             write(file_descriptor[1],&res,sizeof(int));
  1013.             close(file_descriptor[0]);
  1014.             close(file_descriptor[1]);
  1015.             return -2;
  1016.         }
  1017.         else
  1018.         {
  1019.             wait(NULL); // программа основного shell
  1020.         }
  1021.     }
  1022.     if ((base[i]!=NULL)&&(strcmp(base[i],";")==0))
  1023.     {
  1024.         temp=base[i];
  1025.         base[i]=NULL;
  1026.         res=logic(lastcom,0);
  1027.         base[i]=temp;
  1028.         if (res!=0)
  1029.         {
  1030.             return (-2); // возврат в теле одного из сыновей основого shell, либо в случае ошибки fork в pipeline
  1031.         }
  1032.     }
  1033.     if (base[i]!=NULL)
  1034.     {
  1035.         i++;
  1036.         lastcom=base+i;
  1037.         goto jmp;
  1038.     }
  1039.     //на данный момент не выполнился последний нефоновый процесс (ситуацию "proc &" рассматриваем как proc и пустой процесс)
  1040.     return (logic(lastcom,0));
  1041. }
  1042.  
  1043.  
  1044. int main (int argc, char **argv)
  1045. {
  1046.     signal(SIGINT, SIG_IGN);
  1047.     signal(SIGUSR1, sighndlr);
  1048.     int check_end, check=0, input_descriptor;
  1049.     char *str, **base;
  1050.     if (argc==1)
  1051.     {
  1052.         input_descriptor=dup(0);
  1053.     }
  1054.     else
  1055.     {
  1056.         if (argc==2)
  1057.         {
  1058.             input_descriptor=open(argv[1], O_RDONLY);
  1059.             check=1;
  1060.             if (input_descriptor==-1)
  1061.             {
  1062.                 printf("Нет доступа к файлу\n");
  1063.                 return 0;
  1064.             }
  1065.         }
  1066.         else
  1067.         {
  1068.             printf("Некорректное число аргументов командной строки\n");
  1069.             return 0;
  1070.         }
  1071.     }
  1072.    
  1073.     do {
  1074.         printf("MyShell:\n");
  1075.         str=read_line(input_descriptor,&check_end);
  1076.         base=divide_to_lexemes(str);
  1077.         //printf("В массив строк занесены следующие строки\n");
  1078.         //all_str_output(base);
  1079.         if (background(base)==-2)
  1080.         {
  1081.             freedom(base);
  1082.             free(str);
  1083.             return (-2); // возврат либо в теле, некорректно сработавшего шелл (не сработал fork()), либо в теле сыновнего процесса, в котором не сработал exec,
  1084.             // либо в теле каких-то промежуточных процессов-копий основного шелл
  1085.         }
  1086.         freedom(base);
  1087.         free(str);
  1088.     } while (check_end==0);
  1089.     if (check==1)
  1090.     {
  1091.         close(input_descriptor);
  1092.     }
  1093.     return 0;
  1094. }
Add Comment
Please, Sign In to add comment