#include #include #include #include #include #include #include #include static sigjmp_buf restart_jmp_buf; static const int restart_value = 69; static volatile sig_atomic_t jump_active = 0; void sigint_handler(int signo) { if(!jump_active) { return; } siglongjmp(restart_jmp_buf, restart_value); } static constexpr size_t max_line = 1024; static char string_buffer[max_line]; char* readline(char* print, FILE* stream) { if(print) { printf("%s", print); } if(fgets(string_buffer, max_line, stream) == NULL) { if (feof(stdin)) { return NULL; // Ctrl+D } if(ferror(stream)) { perror("fgets error"); clearerr(stdin); return NULL; } return NULL; } size_t length = strlen(string_buffer); //Remove trailing \n if (length > 0 && string_buffer[length - 1] == '\n') { string_buffer[length - 1] = '\0'; } return string_buffer; } char** split_input(char* input) { const size_t alloc_size = ((strlen(input) + 1) / 2) + 1; char** command = malloc(alloc_size * sizeof(char*)); if (command == NULL) { perror("malloc failed"); exit(1); } const char* separator = " "; char* parsed; uint32_t index = 0; parsed = strtok(input, separator); while (parsed != NULL) { command[index] = parsed; index++; parsed = strtok(NULL, separator); } command[index] = NULL; return command; } int cd(char* path) { return chdir(path); } int main(int argc, const char* argv[]) { FILE* stream = stdin; char* prompt = "arsh> "; if(argc == 2) { FILE* file = fopen(argv[1], "r"); if(file) { stream = file; prompt = NULL; } } struct sigaction s; s.sa_handler = sigint_handler; sigemptyset(&s.sa_mask); s.sa_flags = SA_RESTART; struct sigaction s_old; sigaction(SIGINT, &s, &s_old); int stat_loc; if(sigsetjmp(restart_jmp_buf, 1) == restart_value) { printf("\n"); } jump_active = 1; while(true) { char* input = readline(prompt, stream); if(input == NULL) //CTRL + D { if(prompt) { printf("\nexit\n"); } exit(0); } // After that line you need cleanup char** command = split_input(input); if(command[0] == NULL) { goto cleanup; } if(strlen(command[0]) >= 1 && command[0][0] == '#') { goto cleanup; } if(strcmp(command[0], "cd") == 0) { if (cd(command[1]) < 0) { perror(command[1]); } goto cleanup; //skip fork() } if(strcmp(command[0], "exit") == 0) { int32_t status_code = command[1] != NULL ? atoi(command[1]) : 0; exit(status_code); } pid_t child_pid = fork(); if (child_pid < 0) { perror("Fork failed"); exit(1); } if (child_pid == 0) { sigaction(SIGINT, &s_old, NULL); //never returns if call is successful if(execvp(command[0], command) < 0) { perror(command[0]); exit(1); } } else { waitpid(child_pid, &stat_loc, WUNTRACED); } cleanup: free(command); } }