#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) { if(print) { printf("%s", print); } if((fgets(string_buffer, max_line, stdin) == NULL) && ferror(stdin)) { perror("fgets error"); } size_t length = strlen(string_buffer); if(length == 0) { return NULL; } //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() { 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("arsh> "); if(input == NULL) //CTRL + D { printf("\nexit\n"); exit(0); } char** command = split_input(input); if(command[0] == NULL) { 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); } }