Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/wait.h>
- #include <sys/types.h>
- #include <signal.h>
- enum states {NONE, OUT, APPEND_STATES, IN, AMPERSAND_STATES, CONV_STATES, OR, AND, SEMI, BRACKETOPEN, BRACKETCLOSE }; //
- struct cmd {
- char **argv;//массив на выполнение
- int argc;//кол-во слов
- char *infile;
- char *outfile;
- int append; // >>
- int back_ground; // background process
- struct cmd * conveyor;
- struct cmd * logic;
- struct cmd * brackets;
- enum states operation;
- };
- struct cmd struct_noun = {};
- int is_special(char simvol) {
- return (simvol=='(') || (simvol==')') || (simvol=='&') || (simvol=='|') || (simvol==';') || (simvol=='>') || (simvol=='<');
- }
- // структура для хранения пидов фоновых процессов
- typedef struct pnode * process_list;
- process_list back_ground_pids = NULL; // список фоновых процессов
- struct pnode {
- pid_t process_id;
- int msg;
- process_list next;
- };
- // добавление процесса к списку процессов
- void add_list(process_list *list, pid_t process_id, int msg) {
- process_list pointer_main;
- pointer_main = malloc(sizeof(*pointer_main));
- pointer_main->process_id = process_id;
- pointer_main->msg = msg;
- pointer_main->next = *list;
- *list = list;
- }
- // удаление процесса из списка
- void remove_list(process_list *list, pid_t process_id) {
- process_list pointer_main;
- if (*list == NULL) {
- return;
- }
- if ((*list)->process_id == process_id) {
- pointer_main = *list;
- *list = (*list) -> next;
- free(pointer_main);
- } else {
- remove_list(&(*list) -> next, process_id);
- }
- }
- // уничтожение списка фоновых процессов с попыткой удалить зомби
- void back_ground_destroy_list(process_list list) {
- process_list pointer_main;
- if (list == NULL) {
- return;
- }
- pointer_main = list;
- waitpid(pointer_main->process_id,NULL,WNOHANG);
- back_ground_destroy_list(list->next);
- free(pointer_main);
- }
- // проверка завершившихся процессов
- void back_ground_check(process_list *list) {
- process_list pointer_main;
- int status;
- if (*list == NULL) {
- return;
- }
- int pointer_ground_check;
- if ((pointer_ground_check=waitpid((*list)->process_id, &status,WNOHANG)) == (*list)->process_id) {
- if ((*list)->msg) {
- printf("process %d completed\n",(*list)->process_id);
- }
- pointer_main = *list;
- *list = (*list)->next;
- back_ground_check(list);
- free(pointer_main);
- } else {
- //printf("process %d not completed; pointer_main = %d\n",(*list)->process_id, pointer_ground_check);
- back_ground_check(&(*list)->next);
- }
- }
- // остановка всех незавершившихся фоновых процессов при выходе из программы
- void back_ground_stop_all(process_list list) {
- process_list pointer_main = list;
- while (pointer_main != NULL) {
- kill(pointer_main -> process_id, SIGTERM);
- pointer_main = pointer_main -> next;
- }
- back_ground_destroy_list(list);
- }
- char* get_string () {
- char*stroka = NULL;
- int i = 0, size = 1;
- int simvol;
- stroka = malloc (size);
- stroka[0] = '\0';
- do {
- simvol = getchar();
- if (simvol == EOF ) {
- free(stroka);
- return NULL;
- }
- if (simvol == '\n') {
- return stroka;
- }
- if (i + 1 >= size) {
- size += 20;
- stroka = realloc (stroka, size);
- }
- stroka[i] = simvol;
- i++;
- stroka[i]='\0';
- } while (1);
- }
- void add_word (char *** pointer_add_word, int *i, int *size, char *pointer_main, int n) {
- char **pointer_secondary = *pointer_add_word;
- if (*i + 1 >= *size) {
- *size+=10;
- pointer_secondary = realloc(pointer_secondary, (*size) * sizeof(*pointer_secondary));
- }
- pointer_secondary[*i] = malloc(n+1);
- memcpy(pointer_secondary[*i],pointer_main,n);
- pointer_secondary[*i][n]=0;
- (*i)++;
- pointer_secondary[*i] = NULL;
- *pointer_add_word = pointer_secondary;
- }
- char* check(char *pointer_main, enum states *state) {
- *state = NONE;
- switch (*pointer_main) {
- case '<':
- *state = IN;
- pointer_main++;
- break;
- case '>':
- *state = OUT;
- pointer_main++;
- break;
- case '|':
- *state = CONV_STATES;
- pointer_main++;
- break;
- case '&':
- *state = AMPERSAND_STATES;
- pointer_main++;
- break;
- case ';':
- *state = SEMI;
- pointer_main++;
- break;
- case '(':
- *state = BRACKETOPEN;
- pointer_main++;
- break;
- case ')':
- *state = BRACKETCLOSE;
- pointer_main++;
- break;
- default:
- pointer_main++;
- break;
- }
- switch (*state) {
- case OUT:
- if (*pointer_main=='>') {
- *state = APPEND_STATES;
- pointer_main++;
- }
- break;
- case AMPERSAND_STATES:
- if (*pointer_main=='&') {
- *state = AND;
- pointer_main++;
- }
- break;
- case CONV_STATES:
- if (*pointer_main=='|') {
- *state = OR;
- pointer_main++;
- }
- break;
- default:
- break;
- }
- return pointer_main;
- }
- char ** parse_words (char *pointer_main) {
- int space = 1, mode_flag = 0;
- char **pointer_secondary = NULL;
- char *first = NULL;
- enum states state;
- int i =0, size = 0;
- while (*pointer_main != '\0') {
- if (mode_flag) { // "
- if (*pointer_main == '"') {
- add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
- mode_flag = 0;
- space = 1;
- }
- pointer_main++;
- } else if (is_special(*pointer_main)) {
- if (!space) {
- add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
- }
- first = pointer_main;
- pointer_main = check(pointer_main, &state);
- if (pointer_main - first != 0) {
- add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
- }
- space = 1;
- }
- else {
- if (space) {
- if (! isspace(*pointer_main)) {
- first = pointer_main;
- space = 0;
- if (*pointer_main == '"') {
- first = pointer_main+1;
- mode_flag = 1;
- }
- }
- }
- else {
- if (isspace (*pointer_main)) {
- add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
- space =1;
- }
- }
- pointer_main++;
- }
- }
- if (mode_flag == 1) {
- printf ("unclosed \"\n");
- free_words (pointer_secondary);
- return NULL;
- }
- if (!space) {
- add_word(&pointer_secondary, &i, &size, first, pointer_main - first);
- }
- return pointer_secondary;
- }
- void cd (char *word) {
- int point;
- point = chdir (word);
- if ( point == -1) {
- printf ("ERROR CD\n");
- }
- }
- void add_io(char **name, char *word) {
- if (*name != NULL) {
- printf("WARNING: duplicated I/O: %s\n", word);
- return;
- }
- *name = malloc(strlen(word) + 1);
- strcpy(*name, word);
- }
- struct cmd * start_commands(char **words, int *size) {
- struct cmd * pointer_struct = malloc(sizeof(struct cmd)); // запись выделенной памяти
- *pointer_struct = struct_noun; // обнуление
- *size = 10;
- pointer_struct->argv = malloc(*size * sizeof(*pointer_struct->argv));
- pointer_struct->argv[pointer_struct->argc] = malloc(strlen(*words) + 1); //выделение памяти под команды
- strcpy(pointer_struct->argv[pointer_struct->argc],*words); // копирование команды
- pointer_struct->argc++; // argc =1
- pointer_struct->argv[pointer_struct->argc] = NULL;
- return pointer_struct;
- }
- struct cmd * build_cmd(char ***words) {
- if (*words == NULL) {
- return NULL;
- }
- struct cmd *pointer_struct = malloc(sizeof(*pointer_struct)), *begin_place = pointer_struct, *begin_first = pointer_struct; // адрес первой команды
- *pointer_struct = struct_noun; // обнуление
- int size = 0;
- enum states state = NONE; // состояние ожидания имени
- while (**words) {
- if (is_special(***words)) {
- enum states new_state;
- check(**words, &new_state); // записать в new_state тип спец. символа
- if (new_state == AMPERSAND_STATES) {
- begin_place->back_ground = 1; // ****
- } else if (new_state == BRACKETOPEN) {
- switch (state) {
- case OR:
- case AND:
- case SEMI:
- begin_place->logic = start_commands(*words, &size);
- begin_place->operation = state;
- begin_place = begin_place->logic;
- pointer_struct = begin_place;
- state = NONE;
- break;
- case CONV_STATES:
- pointer_struct->conveyor = start_commands(*words, &size);
- pointer_struct = pointer_struct->conveyor;
- state = NONE;
- break;
- case BRACKETOPEN:
- pointer_struct->brackets = start_commands(*words, &size);
- pointer_struct = pointer_struct->brackets;
- break;
- default:
- break;
- }
- (*words)++;
- pointer_struct->brackets = build_cmd(words);
- state = NONE;
- } else if (new_state == BRACKETCLOSE) {
- //(*words)++;
- break;
- } else if (state == NONE) {
- state = new_state;
- } else {
- printf("ERROR: unprocessed special simvol\n");
- }
- } else {
- switch (state) {
- case IN:
- add_io(&pointer_struct->infile, **words);
- state = NONE;
- break;
- case OUT:
- add_io(&pointer_struct->outfile, **words);
- state = NONE;
- break;
- case APPEND_STATES:
- add_io(&pointer_struct->outfile, **words);
- pointer_struct->append = 1;
- state = NONE;
- break;
- case CONV_STATES:
- pointer_struct->conveyor = start_commands(*words, &size);
- pointer_struct = pointer_struct->conveyor;
- state = NONE;
- break;
- case OR:
- case AND:
- case SEMI:
- begin_place->logic = start_commands(*words, &size);
- begin_place->operation = state;
- begin_place = begin_place->logic;
- pointer_struct = begin_place;
- state = NONE;
- break;
- case BRACKETOPEN:
- break;
- default:
- if (pointer_struct->argc + 1 >= size) {
- size+=10;
- pointer_struct->argv = realloc(pointer_struct->argv, size * sizeof(*pointer_struct->argv));
- }
- pointer_struct->argv[pointer_struct->argc] = malloc(strlen(**words) + 1);
- strcpy(pointer_struct->argv[pointer_struct->argc],**words);
- pointer_struct->argc++;
- pointer_struct->argv[pointer_struct->argc] = NULL;
- break;
- }
- }
- (*words)++;
- }
- if (state != NONE) {
- printf("ERROR: syntax\n");
- }
- return begin_first; // возврат первой команды в конвейере
- }
- void print_words (char **pointer_secondary) {
- if (pointer_secondary == NULL) {
- return;
- }
- while (*pointer_secondary != NULL) {
- fprintf (stderr,"%s ", *pointer_secondary);
- pointer_secondary++;
- }
- }
- void print_operation(enum states operation) {
- if (operation == SEMI) {
- fprintf(stderr,"%s ",";");
- } else if (operation == OR) {
- fprintf(stderr,"%s ","||");
- } else if (operation == AND) {
- fprintf(stderr,"%s ","&&");
- } else {
- fprintf(stderr,"none");
- }
- }
- void print_command(struct cmd *begin_place) { // печать команд конвейера для отладки
- struct cmd *command;
- while (begin_place != NULL) {
- command = begin_place;
- while (command != NULL) {
- if (command->brackets != NULL) {
- fprintf(stderr," ( ");
- print_command(command->brackets);
- fprintf(stderr," ) ");
- } else {
- print_words(command->argv);
- }
- if (command->infile != NULL) {
- fprintf(stderr,"<%s ",command->infile);
- }
- if (command->outfile != NULL) {
- if (command->append) {
- fprintf(stderr,">>%s ",command->outfile);
- } else {
- fprintf(stderr,">%s ",command->outfile);
- }
- }
- command = command->conveyor;
- if (command != NULL) {
- fprintf(stderr," | ");
- }
- }
- if (begin_place->logic != NULL) {
- print_operation(begin_place->operation);
- }
- begin_place = begin_place->logic;
- }
- fprintf(stderr,"\n");
- }
- void free_command(struct cmd *begin_place) {
- struct cmd *pointer_main;
- struct cmd *command, *nextbeg;
- while (begin_place != NULL) {
- command = begin_place;
- nextbeg = begin_place->logic;
- while (command != NULL) {
- if (command->brackets!= NULL) {
- free_command(command->brackets);
- } else {
- for (int i=0; i < command->argc; i++) {
- free(command->argv[i]);
- }
- }
- free(command->argv);
- free(command->infile);
- free(command->outfile);
- pointer_main = command;
- command = command -> conveyor; // ****
- free(pointer_main);
- }
- begin_place = nextbeg;
- }
- }
- int run(struct cmd * begin_place) {
- int input; // файл ввода для процесса; -1 если не надо переназначать
- int file_descriptor[2];
- pid_t process_id_optional, wait_pid;
- struct cmd * command;
- int status;
- int result = 1;
- //*begbeg = begin_place; //begin_place - первая команда (нужно для удаления)
- while (begin_place != NULL) {
- command = begin_place;
- file_descriptor[0] = -1;
- file_descriptor[1] = -1;
- // print_command(command);
- while (command != NULL) {
- //printf("command = %pointer_main\n",command);
- if (command->argv && command->argv[0] != NULL && strcmp(command->argv[0], "cd") == 0) {
- cd(command->argv[1]);
- }
- else {
- input = file_descriptor[0]; // определяем стандартный ввод
- if (command->conveyor) { // если есть следующий команды
- pipe(file_descriptor); // создаем неименованный канал
- }
- process_id_optional = fork();
- if (process_id_optional == 0) {
- if (command->conveyor) {
- close(file_descriptor[0]);
- }
- int pointer_f;
- if (input != -1) { // если ввод переопределен, копируем в нулевой канал
- dup2(input,0);
- close(input);
- input = -1;
- }
- if (command->infile) { // или ввод из файла
- pointer_f = open(command->infile, O_RDONLY);
- if (pointer_f == -1) {
- printf("error open file for read: %s\n",command->infile);
- exit(1);
- }
- dup2(pointer_f,0);
- close(pointer_f);
- }
- if (command->outfile) { // вывод
- if (command->append == 0) {
- pointer_f = creat(command->outfile, 0666);
- if (pointer_f == -1) {
- printf("error create file: %s\n",command->outfile);
- exit(1);
- }
- } else {
- pointer_f = open(command->outfile, O_WRONLY | O_APPEND);
- if (pointer_f == -1) {
- printf("error open file for append: %s\n",command->outfile);
- exit(1);
- }
- }
- dup2(pointer_f,1);
- close(pointer_f);
- }
- else
- if (command->conveyor) {
- dup2(file_descriptor[1],1);
- close(file_descriptor[1]);
- file_descriptor[1] = -1;
- }
- if (command->back_ground) {
- pointer_f = open ("/dev/null", O_RDONLY);
- if (pointer_f == -1){
- printf ("can not open file for read: null\n");
- }
- dup2 (pointer_f,0);
- close (pointer_f);
- }
- if (command->brackets != NULL) {
- //fprintf(stderr," launch () \n");
- int res = run(command->brackets);
- exit (1-res);
- } else {
- execvp(command->argv[0], &command->argv[0]);
- printf("error exec %s\n",command->argv[0]);
- exit(0);
- }
- }
- else if (process_id_optional<0) {
- printf ("ERROR");
- }
- if (file_descriptor[1] != -1) {
- close(file_descriptor[1]);
- file_descriptor[1] = -1;
- }
- if (command->back_ground) {
- add_list(&back_ground_pids, process_id_optional, 1);
- }
- else {
- if (command->conveyor != NULL) {
- add_list(&back_ground_pids, process_id_optional, 0);
- } else {
- wait_pid = process_id_optional;
- }
- }
- back_ground_check(&back_ground_pids);
- }
- if (input != -1) {
- close(input);
- input = -1;
- }
- command = command->conveyor;
- } //while
- waitpid(wait_pid, &status, 0);
- result = WIFEXITED(status) && (WEXITSTATUS(status) == 0);
- //print_operation(begin_place->operation);
- //fprintf(stderr," *result=%d; begin_place->logic=%pointer_main; operation=%d\n",result,begin_place->logic,begin_place->operation);
- while ((begin_place->logic != NULL) &&
- (((begin_place->operation == AND) && (result == 0)) ||
- ((begin_place->operation == OR) && (result != 0)))
- ) {
- begin_place = begin_place->logic;
- }
- //fprintf(stderr,"**result=%d; begin_place->logic=%pointer_main\n",result,begin_place->logic);
- begin_place = begin_place->logic;
- //fprintf(stderr,"**result=%d; begin_place=%pointer_main\n",result,begin_place);
- back_ground_check(&back_ground_pids);
- } //while
- return result;
- }
- void ctrlc(int sig){
- printf ("Ctrl+C\n");
- }
- int main(int argc, const char * argv[]) {
- char *line; //входная строка
- char **words; //строка, разбитая на слова
- //process_list frg_pids = NULL; // список фоновых процессов
- struct cmd * command; // конвейер с командами.
- signal (SIGINT, ctrlc);
- printf(":"); fflush(stdout); // fflush - сброс буфера
- while ((line = get_string()) != NULL) { // ввод строки
- words = parse_words(line); // разбор на слова
- free(line);
- char ** begwords = words;
- command = build_cmd(&words); // разбор на команды
- free_words(begwords);
- run(command);
- printf(":"); fflush(stdout); // fflush - сброс буфера
- free(command);
- }
- back_ground_stop_all(back_ground_pids);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement