From 821b146c54330cecba3ed2cc03a0f71ad83e540f Mon Sep 17 00:00:00 2001 From: scratko Date: Sun, 23 Jun 2024 22:35:56 +0300 Subject: Shell-VI release Running processes in a single pgid. Changing foreground group to the group of running processes (if readline doesn't end with &). --- Makefile | 4 +-- shell.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++----------------- shell.h | 65 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 shell.h diff --git a/Makefile b/Makefile index 2bbac5e..9aa167e 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,12 @@ OBJMODULES = $(SRCMODULES:.c=.o) CC = gcc CFLAGS = -Wall -g -c -all: shell-edit +all: shell-VI %.o: %.с %.h $(CC) $(CFLAGS) $< -o $@ -shell-edit: $(OBJMODULES) +shell-VI: $(OBJMODULES) $(CC) $(LIBS) $^ -o $@ -include deps.mk diff --git a/shell.c b/shell.c index 2944f00..36eb916 100644 --- a/shell.c +++ b/shell.c @@ -23,6 +23,22 @@ MAKE_QUEUE_PUSH(p_queue, pid, int) enum modes { word_separation, whole_word }; +static void change_terminal_settings(struct termios *cur_terminal_settings, + struct termios *save_terminal_settings) +{ + tcgetattr(0, save_terminal_settings); + memcpy(cur_terminal_settings, save_terminal_settings, + sizeof(*save_terminal_settings)); + cur_terminal_settings->c_lflag &= ~(ICANON | ECHO); + tcsetattr(0, TCSANOW, cur_terminal_settings); +} + +static void restore_terminal_settings(struct termios *cur_terminal_settings, + struct termios *save_terminal_settings) +{ + tcsetattr(0, TCSANOW, save_terminal_settings); +} + static void show_invitation() { printf("> "); @@ -59,6 +75,7 @@ static void init_params(struct param_type *params, enum modes *current_mode) params->last_execution_status = 0; params->pipeline = 0; params->new_readline = 1; + params->general_pgid = -1; *current_mode = word_separation; } @@ -90,6 +107,17 @@ static void reset_params(struct param_type *params, init_params(params, current_mode); } +static void prepare_for_next_command_on_line(struct param_type *params, + struct w_queue *word_chain, + struct c_queue *cmdlines, + struct dynamic_array *tmp_word) +{ + w_queue_clear(word_chain); + c_queue_clear(cmdlines); + dynarr_reset_array(tmp_word); + clear_filename(params); +} + static void add_letter(int ch, struct dynamic_array *tmp_word, struct param_type *params) { @@ -180,8 +208,11 @@ static void postprocessing(struct w_queue *word_chain, struct c_queue *cmdlines, { clean_up_memory(word_chain, cmdlines, params); close_files(input_fd, output_fd); - if(params->tokens != '&') + if(params->tokens != '&') { wait_for_process_to_complete(pid_store); + signal(SIGTTOU, SIG_IGN); + tcsetpgrp(0, getpid()); + } p_queue_clear(pid_store); } @@ -218,6 +249,15 @@ int is_stream_redirection_set(const struct param_type *params) params->streams.output_stream_to_append; } +static void identify_general_pgid(struct param_type *params, int pid) +{ + if(params->general_pgid == -1) + params->general_pgid = pid; + if(params->tokens != '&') + /* foreground group */ + tcsetpgrp(0, params->general_pgid); +} + static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines, struct param_type *params, int input_fd, int output_fd) @@ -233,12 +273,19 @@ static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines, set_signal_disposition(params); pid = fork(); + /* parent process */ + if(pid) + identify_general_pgid(params, pid); + if(pid == 0) { close(fd[0]); dup2(fd[1], 1); close(fd[1]); if(is_stream_redirection_set(params)) change_streams(input_fd, output_fd, 1, 1); + /* change pgid */ + setpgid(getpid(), params->general_pgid == -1 ? + getpid() : params->general_pgid); execvp(cmdline[0], cmdline); perror(cmdline[0]); exit(1); @@ -270,6 +317,10 @@ static void make_pipeline(struct w_queue *word_chain, struct c_queue *cmdlines, if(c_queue_is_empty(cmdlines)) if(is_stream_redirection_set(params)) change_streams(input_fd, output_fd, 1, 0); + + /* change pgid */ + setpgid(getpid(), params->general_pgid); + execvp(cmdline[0], cmdline); perror(cmdline[0]); exit(1); @@ -359,10 +410,17 @@ static void run_external_program(struct w_queue *word_chain, perror("fork error"); exit(1); } + /* parent process */ + if(pid) + identify_general_pgid(params, pid); + /* child process */ if(pid == 0) { if(is_stream_redirection_set(params)) change_streams(input_fd, output_fd, 0, 0); + /* change pgid */ + setpgid(getpid(), params->general_pgid == -1 ? + getpid() : params->general_pgid); execvp(cmdline[0], cmdline); params->last_execution_status = 1; perror(cmdline[0]); @@ -440,10 +498,13 @@ static void echo_characters(int ch) static void generate_readline(struct readline_type *readline) { + struct termios cur_terminal_settings, save_terminal_settings; enum keys found_key = none; int match_result; char ch; + change_terminal_settings(&cur_terminal_settings, &save_terminal_settings); + while((ch = getchar()) && !readline_termination_condition(ch, readline)) { if(ch == tab) { if(suggestions_for_filename(readline)) { @@ -494,6 +555,7 @@ static void generate_readline(struct readline_type *readline) /* print '\n' to end of readline */ if(ch == new_line) echo_characters(ch); + restore_terminal_settings(&cur_terminal_settings, &save_terminal_settings); } static void command_processing(struct param_type *params, @@ -546,13 +608,15 @@ static void command_processing(struct param_type *params, clean: error_identification(params); last_token = params->tokens; - reset_params(params, current_mode, word_chain, cmdlines, tmp_word, - readline); if(last_token == '&' || last_token == 0 || ch == new_line) { + reset_params(params, current_mode, word_chain, cmdlines, tmp_word, + readline); show_invitation(); generate_readline(readline); - } + } else + prepare_for_next_command_on_line(params, word_chain, cmdlines, + tmp_word); } static void word_separation_processing(int ch, struct param_type *params, @@ -651,35 +715,17 @@ static void whole_word_processing(int ch, struct param_type *params, add_letter(ch, tmp_word, params); } -static void change_terminal_settings(struct termios *cur_terminal_settings, - struct termios *save_terminal_settings) -{ - tcgetattr(0, save_terminal_settings); - memcpy(cur_terminal_settings, save_terminal_settings, - sizeof(*save_terminal_settings)); - cur_terminal_settings->c_lflag &= ~(ICANON | ECHO); - tcsetattr(0, TCSANOW, cur_terminal_settings); -} - -static void restore_terminal_settings(struct termios *cur_terminal_settings, - struct termios *save_terminal_settings) -{ - tcsetattr(0, TCSANOW, save_terminal_settings); -} - int main() { char ch; int i; struct param_type params; - struct termios cur_terminal_settings, save_terminal_settings; struct w_queue word_chain; struct c_queue cmdlines; struct dynamic_array tmp_word; struct readline_type readline; enum modes current_mode = word_separation; - change_terminal_settings(&cur_terminal_settings, &save_terminal_settings); w_queue_init(&word_chain); c_queue_init(&cmdlines); dynarr_create_array(&tmp_word); @@ -710,8 +756,6 @@ int main() &tmp_word); i = params.new_readline ? 0 : i + 1; } - - restore_terminal_settings(&cur_terminal_settings, &save_terminal_settings); putchar(new_line); dynarr_clear(&tmp_word); readline_clear(&readline); diff --git a/shell.h b/shell.h new file mode 100644 index 0000000..b3dd93d --- /dev/null +++ b/shell.h @@ -0,0 +1,65 @@ +#ifndef SHELL_H_SENTRY +#define SHELL_H_SENTRY + +#include "dynamic_array.h" +#include "queue.h" + +enum { + /* CTRL-D */ + end_of_file = 4, + new_line = 10, + whitespace = ' ', + tab = 9, + esc = 27, + backslash = '\\', + double_quotes = '"' +}; + +/* two-letter tokens */ +enum { + append = '>' + 1, + and = '&' + 1, + or = '|' + 1 +}; + +/* error codes */ +enum { + err_filename_expected = 1, + err_redirect_stream_again = 2, + err_redirect_stream_in_pipeline = 3, + err_bg_process = 4, + err_empty_command = 5, + err_extra_chars_after_filename = 6, + err_odd_double_quotes = 7 +}; + +/* storing file names to redirect standard input/output streams */ +struct io_type { + char *input_stream; + char *output_stream; + char *output_stream_to_append; +}; + +struct param_type { + int is_word; + int escape_sequences; + unsigned int double_quotes_counter; + char stored_symbol; + int empty_word_flag; + int tokens; + int wrong_command; + struct io_type streams; + int last_execution_status; + int pipeline; + int new_readline; + int general_pgid; +}; + +int filename_waiting(struct param_type *params); +void add_filename(struct dynamic_array *tmp_word, struct param_type *params); +void add_word(struct w_queue *word_chain, struct dynamic_array *tmp_word, + struct param_type *params); +int is_stream_redirection_set(const struct param_type *params); +char** create_cmdline(const struct w_queue *word_chain, int word_counter); + +#endif -- cgit v1.2.3