Advertisement
romko11l

Untitled

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