SHARE
TWEET

Untitled

a guest Dec 3rd, 2019 68 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <unistd.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8.  
  9. #include <sys/wait.h>
  10. #include <sys/types.h>
  11. #include <signal.h>
  12.  
  13. enum states {NONE, OUT, APPEND_STATES, IN, AMPERSAND_STATES, CONV_STATES, OR, AND, SEMI, BRACKETOPEN, BRACKETCLOSE }; //
  14.  
  15. struct cmd {
  16.     char **argv;//массив на выполнение
  17.     int argc;//кол-во слов
  18.     char *infile;
  19.     char *outfile;
  20.     int append;       // >>
  21.     int back_ground;          // background process
  22.     struct cmd * conveyor;
  23.     struct cmd * logic;
  24.     struct cmd * brackets;
  25.     enum states operation;
  26. };
  27. struct cmd struct_noun = {};
  28.  
  29. int is_special(char simvol) {
  30.     return (simvol=='(') || (simvol==')') || (simvol=='&') || (simvol=='|') || (simvol==';') || (simvol=='>') || (simvol=='<');
  31. }
  32.  
  33. // структура для хранения пидов фоновых процессов
  34. typedef struct pnode * process_list;
  35. process_list back_ground_pids = NULL; // список фоновых процессов
  36.  
  37. struct pnode {
  38.     pid_t process_id;
  39.     int msg;
  40.     process_list next;
  41. };
  42.  
  43. // добавление процесса к списку процессов
  44. void add_list(process_list *list, pid_t process_id, int msg) {
  45.     process_list pointer_main;
  46.     pointer_main = malloc(sizeof(*pointer_main));
  47.     pointer_main->process_id = process_id;
  48.     pointer_main->msg = msg;
  49.     pointer_main->next = *list;
  50.     *list = list;
  51. }
  52.  
  53. // удаление процесса из списка
  54. void remove_list(process_list *list, pid_t process_id) {
  55.     process_list pointer_main;
  56.  
  57.  
  58.     if (*list == NULL) {
  59.         return;
  60.     }
  61.     if ((*list)->process_id == process_id) {
  62.         pointer_main = *list;
  63.         *list = (*list) -> next;
  64.         free(pointer_main);
  65.     } else {
  66.         remove_list(&(*list) -> next, process_id);
  67.     }
  68. }
  69.  
  70. // уничтожение списка фоновых процессов с попыткой удалить зомби
  71. void back_ground_destroy_list(process_list list) {
  72.     process_list pointer_main;
  73.     if (list == NULL) {
  74.         return;
  75.     }
  76.     pointer_main = list;
  77.     waitpid(pointer_main->process_id,NULL,WNOHANG);
  78.     back_ground_destroy_list(list->next);
  79.     free(pointer_main);
  80. }
  81.  
  82. // проверка завершившихся процессов
  83. void back_ground_check(process_list *list) {
  84.     process_list pointer_main;
  85.     int status;
  86.     if (*list == NULL) {
  87.         return;
  88.     }
  89.     int pointer_ground_check;
  90.     if ((pointer_ground_check=waitpid((*list)->process_id, &status,WNOHANG)) == (*list)->process_id) {
  91.         if ((*list)->msg) {
  92.             printf("process %d completed\n",(*list)->process_id);
  93.         }
  94.         pointer_main = *list;
  95.         *list = (*list)->next;
  96.         back_ground_check(list);
  97.         free(pointer_main);
  98.     } else {
  99.         //printf("process %d not completed; pointer_main = %d\n",(*list)->process_id, pointer_ground_check);
  100.         back_ground_check(&(*list)->next);
  101.     }
  102. }
  103.  
  104. // остановка всех незавершившихся фоновых процессов при выходе из программы
  105. void back_ground_stop_all(process_list list) {
  106.     process_list pointer_main = list;
  107.     while (pointer_main != NULL) {
  108.         kill(pointer_main -> process_id, SIGTERM);
  109.         pointer_main = pointer_main -> next;
  110.     }
  111.     back_ground_destroy_list(list);
  112. }
  113.  
  114. char* get_string () {
  115.     char*stroka = NULL;
  116.     int i = 0, size = 1;
  117.     int simvol;
  118.     stroka = malloc (size);
  119.     stroka[0] = '\0';
  120.     do {
  121.         simvol = getchar();
  122.         if (simvol == EOF ) {
  123.             free(stroka);
  124.             return NULL;
  125.         }
  126.         if (simvol == '\n') {
  127.             return stroka;
  128.         }
  129.         if (i + 1 >= size) {
  130.             size += 20;
  131.             stroka = realloc (stroka, size);
  132.         }
  133.         stroka[i] = simvol;
  134.         i++;
  135.         stroka[i]='\0';
  136.     } while (1);
  137. }
  138.  
  139. void add_word (char *** pointer_add_word, int *i, int *size, char *pointer_main, int n) {
  140.     char **pointer_secondary = *pointer_add_word;
  141.     if (*i + 1 >= *size) {
  142.         *size+=10;
  143.         pointer_secondary = realloc(pointer_secondary, (*size) * sizeof(*pointer_secondary));
  144.     }
  145.     pointer_secondary[*i] = malloc(n+1);
  146.     memcpy(pointer_secondary[*i],pointer_main,n);
  147.     pointer_secondary[*i][n]=0;
  148.     (*i)++;
  149.     pointer_secondary[*i] = NULL;
  150.     *pointer_add_word = pointer_secondary;
  151. }
  152.  
  153.  
  154. char* check(char *pointer_main, enum states *state) {
  155.     *state = NONE;
  156.     switch (*pointer_main) {
  157.         case '<':
  158.             *state = IN;
  159.             pointer_main++;
  160.             break;
  161.         case '>':
  162.             *state = OUT;
  163.             pointer_main++;
  164.             break;
  165.         case '|':
  166.             *state = CONV_STATES;
  167.             pointer_main++;
  168.             break;
  169.         case '&':
  170.             *state = AMPERSAND_STATES;
  171.             pointer_main++;
  172.             break;
  173.         case ';':
  174.             *state = SEMI;
  175.             pointer_main++;
  176.             break;
  177.         case '(':
  178.             *state = BRACKETOPEN;
  179.             pointer_main++;
  180.             break;
  181.         case ')':
  182.             *state = BRACKETCLOSE;
  183.             pointer_main++;
  184.             break;
  185.         default:
  186.             pointer_main++;
  187.             break;
  188.     }
  189.     switch (*state) {
  190.         case OUT:
  191.             if (*pointer_main=='>') {
  192.                 *state = APPEND_STATES;
  193.                 pointer_main++;
  194.             }
  195.             break;
  196.         case AMPERSAND_STATES:
  197.             if (*pointer_main=='&') {
  198.                 *state = AND;
  199.                 pointer_main++;
  200.             }
  201.             break;
  202.         case CONV_STATES:
  203.             if (*pointer_main=='|') {
  204.                 *state = OR;
  205.                 pointer_main++;
  206.             }
  207.             break;
  208.         default:
  209.             break;
  210.     }
  211.     return pointer_main;
  212. }
  213.  
  214. char ** parse_words (char *pointer_main) {
  215.     int space = 1, mode_flag = 0;
  216.     char **pointer_secondary = NULL;
  217.     char *first = NULL;
  218.     enum states state;
  219.     int i =0, size = 0;
  220.     while (*pointer_main != '\0') {
  221.         if (mode_flag) { // "
  222.             if (*pointer_main == '"') {
  223.                 add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  224.                 mode_flag = 0;
  225.                 space = 1;
  226.             }
  227.             pointer_main++;
  228.         } else if (is_special(*pointer_main)) {
  229.             if (!space) {
  230.                 add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  231.             }
  232.             first = pointer_main;
  233.             pointer_main = check(pointer_main, &state);
  234.             if (pointer_main - first != 0) {
  235.                 add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  236.             }
  237.             space = 1;
  238.         }
  239.         else {
  240.             if (space) {
  241.                 if (! isspace(*pointer_main)) {
  242.                     first = pointer_main;
  243.                     space = 0;
  244.                     if (*pointer_main == '"') {
  245.                         first = pointer_main+1;
  246.                         mode_flag = 1;
  247.                     }
  248.                 }
  249.             }
  250.             else {
  251.                 if (isspace (*pointer_main)) {
  252.                     add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  253.                     space =1;
  254.                 }
  255.             }
  256.             pointer_main++;
  257.         }
  258.     }
  259.     if (mode_flag == 1) {
  260.         printf ("unclosed \"\n");
  261.         free_words (pointer_secondary);
  262.         return NULL;
  263.     }
  264.     if (!space) {
  265.         add_word(&pointer_secondary, &i, &size, first, pointer_main - first);
  266.     }
  267.     return pointer_secondary;
  268. }
  269.  
  270. void cd (char *word) {
  271.     int point;
  272.     point = chdir (word);
  273.     if ( point == -1) {
  274.         printf ("ERROR CD\n");
  275.     }
  276. }
  277.  
  278. void add_io(char **name, char *word) {
  279.     if (*name != NULL) {
  280.         printf("WARNING: duplicated I/O: %s\n", word);
  281.         return;
  282.     }
  283.     *name = malloc(strlen(word) + 1);
  284.     strcpy(*name, word);
  285. }
  286.  
  287. struct cmd * start_commands(char **words, int *size) {
  288.     struct cmd * pointer_struct = malloc(sizeof(struct cmd)); // запись выделенной памяти
  289.     *pointer_struct = struct_noun; // обнуление
  290.     *size = 10;
  291.     pointer_struct->argv = malloc(*size * sizeof(*pointer_struct->argv));
  292.     pointer_struct->argv[pointer_struct->argc] = malloc(strlen(*words) + 1); //выделение памяти под команды
  293.     strcpy(pointer_struct->argv[pointer_struct->argc],*words); // копирование команды
  294.     pointer_struct->argc++; // argc =1
  295.     pointer_struct->argv[pointer_struct->argc] = NULL;
  296.     return pointer_struct;
  297. }
  298.  
  299. struct cmd * build_cmd(char ***words) {
  300.     if (*words == NULL) {
  301.         return NULL;
  302.     }
  303.  
  304.     struct cmd *pointer_struct = malloc(sizeof(*pointer_struct)), *begin_place = pointer_struct, *begin_first = pointer_struct; // адрес первой команды
  305.     *pointer_struct = struct_noun; // обнуление
  306.     int size = 0;
  307.     enum states state = NONE; // состояние ожидания имени
  308.  
  309.     while (**words) {
  310.         if (is_special(***words)) {
  311.             enum states new_state;
  312.             check(**words, &new_state); // записать в new_state тип спец. символа
  313.             if (new_state == AMPERSAND_STATES) {
  314.                 begin_place->back_ground = 1; // ****
  315.             } else if (new_state == BRACKETOPEN) {
  316.                 switch (state) {
  317.                 case OR:
  318.                 case AND:
  319.                 case SEMI:
  320.                     begin_place->logic = start_commands(*words, &size);
  321.                     begin_place->operation = state;
  322.                     begin_place = begin_place->logic;
  323.                     pointer_struct = begin_place;
  324.                     state = NONE;
  325.                     break;
  326.                 case CONV_STATES:
  327.                     pointer_struct->conveyor = start_commands(*words, &size);
  328.                     pointer_struct = pointer_struct->conveyor;
  329.                     state = NONE;
  330.                     break;
  331.                 case BRACKETOPEN:
  332.                     pointer_struct->brackets = start_commands(*words, &size);
  333.                     pointer_struct = pointer_struct->brackets;
  334.  
  335.                     break;
  336.                 default:
  337.                     break;
  338.                 }
  339.                 (*words)++;
  340.                 pointer_struct->brackets = build_cmd(words);
  341.                 state = NONE;
  342.             } else if (new_state == BRACKETCLOSE) {
  343.                 //(*words)++;
  344.                 break;
  345.             } else if (state == NONE) {
  346.                 state = new_state;
  347.             } else {
  348.                 printf("ERROR: unprocessed special simvol\n");
  349.             }
  350.         } else {
  351.             switch (state) {
  352.                 case IN:
  353.                     add_io(&pointer_struct->infile, **words);
  354.                     state = NONE;
  355.                     break;
  356.                 case OUT:
  357.                     add_io(&pointer_struct->outfile, **words);
  358.                     state = NONE;
  359.                     break;
  360.                 case APPEND_STATES:
  361.                     add_io(&pointer_struct->outfile, **words);
  362.                     pointer_struct->append = 1;
  363.                     state = NONE;
  364.                     break;
  365.                 case CONV_STATES:
  366.                     pointer_struct->conveyor = start_commands(*words, &size);
  367.                     pointer_struct = pointer_struct->conveyor;
  368.                     state = NONE;
  369.                     break;
  370.                 case OR:
  371.                 case AND:
  372.                 case SEMI:
  373.                     begin_place->logic = start_commands(*words, &size);
  374.                     begin_place->operation = state;
  375.                     begin_place = begin_place->logic;
  376.                     pointer_struct = begin_place;
  377.                     state = NONE;
  378.                     break;
  379.                 case BRACKETOPEN:
  380.  
  381.                     break;
  382.                 default:
  383.                     if (pointer_struct->argc + 1 >= size) {
  384.                         size+=10;
  385.                         pointer_struct->argv = realloc(pointer_struct->argv, size * sizeof(*pointer_struct->argv));
  386.                     }
  387.                     pointer_struct->argv[pointer_struct->argc] = malloc(strlen(**words) + 1);
  388.                     strcpy(pointer_struct->argv[pointer_struct->argc],**words);
  389.                     pointer_struct->argc++;
  390.                     pointer_struct->argv[pointer_struct->argc] = NULL;
  391.                     break;
  392.             }
  393.         }
  394.         (*words)++;
  395.     }
  396.     if (state != NONE) {
  397.         printf("ERROR: syntax\n");
  398.     }
  399.     return begin_first; // возврат первой команды в конвейере
  400. }
  401.  
  402. void print_words (char **pointer_secondary) {
  403.     if (pointer_secondary == NULL) {
  404.         return;
  405.     }
  406.     while (*pointer_secondary != NULL) {
  407.         fprintf (stderr,"%s ", *pointer_secondary);
  408.         pointer_secondary++;
  409.     }
  410. }
  411.  
  412. void print_operation(enum states operation) {
  413.     if (operation == SEMI) {
  414.         fprintf(stderr,"%s ",";");
  415.     } else if (operation == OR) {
  416.         fprintf(stderr,"%s ","||");
  417.     } else if (operation == AND) {
  418.         fprintf(stderr,"%s ","&&");
  419.     } else {
  420.        fprintf(stderr,"none");
  421.     }
  422. }
  423.  
  424. void print_command(struct cmd *begin_place) { // печать команд конвейера для отладки
  425.     struct cmd *command;
  426.     while (begin_place != NULL) {
  427.         command = begin_place;
  428.         while (command != NULL) {
  429.             if (command->brackets != NULL) {
  430.                 fprintf(stderr," ( ");
  431.                 print_command(command->brackets);
  432.                 fprintf(stderr," ) ");
  433.             } else {
  434.                 print_words(command->argv);
  435.             }
  436.             if (command->infile != NULL) {
  437.                 fprintf(stderr,"<%s ",command->infile);
  438.             }
  439.             if (command->outfile != NULL) {
  440.                 if (command->append) {
  441.                     fprintf(stderr,">>%s ",command->outfile);
  442.                 } else {
  443.                     fprintf(stderr,">%s ",command->outfile);
  444.                 }
  445.             }
  446.             command = command->conveyor;
  447.             if (command != NULL) {
  448.                 fprintf(stderr," | ");
  449.             }
  450.         }
  451.         if (begin_place->logic != NULL) {
  452.             print_operation(begin_place->operation);
  453.         }
  454.         begin_place = begin_place->logic;
  455.     }
  456.     fprintf(stderr,"\n");
  457. }
  458.  
  459. void free_command(struct cmd *begin_place) {
  460.     struct cmd *pointer_main;
  461.     struct cmd *command, *nextbeg;
  462.     while (begin_place != NULL) {
  463.         command = begin_place;
  464.         nextbeg = begin_place->logic;
  465.         while (command != NULL) {
  466.             if (command->brackets!= NULL) {
  467.                 free_command(command->brackets);
  468.             } else {
  469.                 for (int i=0; i < command->argc; i++) {
  470.                     free(command->argv[i]);
  471.                 }
  472.             }
  473.             free(command->argv);
  474.             free(command->infile);
  475.             free(command->outfile);
  476.             pointer_main = command;
  477.             command = command -> conveyor; // ****
  478.             free(pointer_main);
  479.         }
  480.         begin_place = nextbeg;
  481.     }
  482. }
  483.  
  484. int run(struct cmd * begin_place) {
  485.     int input;  // файл ввода для процесса; -1 если не надо переназначать
  486.     int file_descriptor[2];
  487.     pid_t process_id_optional, wait_pid;
  488.     struct cmd * command;
  489.     int status;
  490.     int result = 1;
  491.  
  492.     //*begbeg = begin_place; //begin_place - первая команда (нужно для удаления)
  493.     while (begin_place != NULL) {
  494.         command = begin_place;
  495.         file_descriptor[0] = -1;
  496.         file_descriptor[1] = -1;
  497. //        print_command(command);
  498.         while (command != NULL) {
  499.             //printf("command = %pointer_main\n",command);
  500.                 if (command->argv && command->argv[0] != NULL && strcmp(command->argv[0], "cd") == 0) {
  501.                     cd(command->argv[1]);
  502.                 }
  503.                 else {
  504.                     input = file_descriptor[0];          // определяем стандартный ввод
  505.                     if (command->conveyor) {    // если есть следующий команды
  506.                         pipe(file_descriptor);           // создаем неименованный канал
  507.                     }
  508.                     process_id_optional = fork();
  509.                     if (process_id_optional == 0) {
  510.                         if (command->conveyor) {
  511.                             close(file_descriptor[0]);
  512.                         }
  513.                         int pointer_f;
  514.                         if (input != -1) {  // если ввод переопределен, копируем в нулевой канал
  515.                             dup2(input,0);
  516.                             close(input);
  517.                             input = -1;
  518.                         }
  519.                         if (command->infile) { // или ввод из файла
  520.                             pointer_f = open(command->infile, O_RDONLY);
  521.                             if (pointer_f == -1) {
  522.                                 printf("error open file for read: %s\n",command->infile);
  523.                                 exit(1);
  524.                             }
  525.                             dup2(pointer_f,0);
  526.                             close(pointer_f);
  527.                         }
  528.                         if (command->outfile) {  // вывод
  529.                             if (command->append == 0) {
  530.                                 pointer_f = creat(command->outfile, 0666);
  531.                                 if (pointer_f == -1) {
  532.                                     printf("error create file: %s\n",command->outfile);
  533.                                     exit(1);
  534.                                 }
  535.                             } else {
  536.                                 pointer_f = open(command->outfile, O_WRONLY | O_APPEND);
  537.                                 if (pointer_f == -1) {
  538.                                     printf("error open file for append: %s\n",command->outfile);
  539.                                     exit(1);
  540.                                 }
  541.                             }
  542.                             dup2(pointer_f,1);
  543.                             close(pointer_f);
  544.                         }
  545.                         else
  546.                             if (command->conveyor) {
  547.                                 dup2(file_descriptor[1],1);
  548.                                 close(file_descriptor[1]);
  549.                                 file_descriptor[1] = -1;
  550.                             }
  551.                         if (command->back_ground) {
  552.                             pointer_f = open ("/dev/null", O_RDONLY);
  553.                             if (pointer_f == -1){
  554.                                 printf ("can not open file for read: null\n");
  555.                             }
  556.                             dup2 (pointer_f,0);
  557.                             close (pointer_f);
  558.                         }
  559.  
  560.                         if (command->brackets != NULL) {
  561.                             //fprintf(stderr," launch () \n");
  562.                             int res = run(command->brackets);
  563.                             exit (1-res);
  564.                         } else {
  565.                             execvp(command->argv[0], &command->argv[0]);
  566.                             printf("error exec %s\n",command->argv[0]);
  567.                             exit(0);
  568.                         }
  569.                     }
  570.                     else if (process_id_optional<0) {
  571.                         printf ("ERROR");
  572.                     }
  573.                     if (file_descriptor[1] != -1) {
  574.                         close(file_descriptor[1]);
  575.                         file_descriptor[1] = -1;
  576.                     }
  577.                     if (command->back_ground) {
  578.                         add_list(&back_ground_pids, process_id_optional, 1);
  579.                     }
  580.                     else {
  581.                         if (command->conveyor != NULL) {
  582.                             add_list(&back_ground_pids, process_id_optional, 0);
  583.                         } else {
  584.                             wait_pid = process_id_optional;
  585.                         }
  586.                     }
  587.                     back_ground_check(&back_ground_pids);
  588.                 }
  589.                 if (input != -1) {
  590.                     close(input);
  591.                     input = -1;
  592.                 }
  593.            
  594.             command = command->conveyor;
  595.         } //while
  596.         waitpid(wait_pid, &status, 0);
  597.         result = WIFEXITED(status) && (WEXITSTATUS(status) == 0);
  598. //print_operation(begin_place->operation);
  599. //fprintf(stderr," *result=%d; begin_place->logic=%pointer_main; operation=%d\n",result,begin_place->logic,begin_place->operation);
  600.         while ((begin_place->logic != NULL) &&
  601.                (((begin_place->operation == AND) && (result == 0)) ||
  602.                 ((begin_place->operation == OR) && (result != 0)))
  603.               ) {
  604.              begin_place = begin_place->logic;
  605.         }
  606. //fprintf(stderr,"**result=%d; begin_place->logic=%pointer_main\n",result,begin_place->logic);
  607.         begin_place = begin_place->logic;
  608. //fprintf(stderr,"**result=%d; begin_place=%pointer_main\n",result,begin_place);
  609.         back_ground_check(&back_ground_pids);
  610.     } //while
  611.     return result;
  612. }
  613.  
  614. void ctrlc(int sig){
  615.     printf ("Ctrl+C\n");
  616. }
  617.  
  618.  
  619. int main(int argc, const char * argv[]) {
  620.     char *line; //входная строка
  621.     char **words; //строка, разбитая на слова
  622.     //process_list frg_pids = NULL; // список фоновых процессов
  623.     struct cmd * command; // конвейер с командами.
  624.  
  625.  
  626.     signal (SIGINT, ctrlc);
  627.     printf(":"); fflush(stdout); // fflush - сброс буфера
  628.     while ((line = get_string()) != NULL) { // ввод строки
  629.         words = parse_words(line); // разбор на слова
  630.         free(line);
  631.         char ** begwords = words;
  632.         command = build_cmd(&words); // разбор на команды
  633.         free_words(begwords);
  634.         run(command);
  635.         printf(":"); fflush(stdout); // fflush - сброс буфера
  636.         free(command);
  637.     }
  638.     back_ground_stop_all(back_ground_pids);
  639.     return 0;
  640. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top