From 83061ca384a255adb3089efed868e90b01126f1e Mon Sep 17 00:00:00 2001 From: Trent Huber Date: Tue, 6 May 2025 02:44:28 -0400 Subject: [PATCH] Improve error handling --- build.c | 1 + external/cbs | 2 +- main.c | 129 +++++++++++++++++++++------------------------------ 3 files changed, 56 insertions(+), 76 deletions(-) diff --git a/build.c b/build.c index 2ab0877..bb28a1b 100644 --- a/build.c +++ b/build.c @@ -4,6 +4,7 @@ int main(void) { build(NULL); compile("main", NULL); + load('x', "ash", "main", NULL); return EXIT_SUCCESS; diff --git a/external/cbs b/external/cbs index 47c262d..51d2489 160000 --- a/external/cbs +++ b/external/cbs @@ -1 +1 @@ -Subproject commit 47c262dc02e5f6ed3dba9e092a5f750084bfad95 +Subproject commit 51d2489cfcf1c245db14c3a9e7c9e40e6a550f4c diff --git a/main.c b/main.c index e707e55..6647dea 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,27 +7,30 @@ #include #include -#define BUFLEN 1024 - -void nlprompt(int sig) { - (void)sig; - - printf("\n%% "); +void prompt(int sig) { + if (sig == SIGINT) printf("\n"); + printf("%% "); fflush(stdout); } +#define BUFLEN 1024 + char **tokenize(char *p) { size_t i; static char *result[BUFLEN / 2]; + while (*p == ' ') ++p; for (i = 0; *p != '\n'; ++i) { result[i] = p; while (*p != ' ' && *p != '\n') ++p; *p++ = '\0'; - if (*p == '\0') break; + if (*p == '\0') { + ++i; + break; + } while (*p == ' ') ++p; } - result[i + 1] = NULL; + result[i] = NULL; return result; } @@ -46,44 +50,18 @@ pid_t popbgps(void) { return bgps.sp != bgps.bp ? bgps.pgids[bgps.sp--] : -1; } +pid_t self; + void await(pid_t cpgid) { int status; - pid_t pgid; - if (waitpid(cpgid, &status, WUNTRACED) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to await previous command: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - if (!WIFSTOPPED(status)) { // Reap + if (waitpid(cpgid, &status, WUNTRACED) != -1 && !WIFSTOPPED(status)) { while (waitpid(-cpgid, NULL, 0) != -1); - if (errno != ECHILD) { - dprintf(STDERR_FILENO, "ash: Unable to await previous command: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - errno = 0; - } - if ((pgid = getpgid(0)) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to get group process id: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - if (signal(SIGTTOU, SIG_IGN) == SIG_ERR) { - dprintf(STDERR_FILENO, "ash: Unable to ignore SIGTTOU signal: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - if (tcsetpgrp(STDIN_FILENO, pgid) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to set tty foreground " - "process group: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - if (signal(SIGTTOU, SIG_DFL) == SIG_ERR) { - dprintf(STDERR_FILENO, "ash: Unable to set SIGTTOU signal: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); + if (errno != ECHILD && killpg(cpgid, SIGKILL) == -1) exit(EXIT_FAILURE); } + if (signal(SIGTTOU, SIG_IGN) == SIG_ERR) exit(EXIT_FAILURE); + if (tcsetpgrp(STDIN_FILENO, self) == -1) exit(EXIT_FAILURE); + if (signal(SIGTTOU, SIG_DFL) == SIG_ERR) warn("Ignoring signal SIGTTOU"); if (WIFSIGNALED(status)) printf("\n"); if (WIFSTOPPED(status)) pushbgps(cpgid); @@ -93,21 +71,21 @@ int builtin(char **tokens) { pid_t fgpgid; if (strcmp(tokens[0], "cd") == 0) { - if (chdir(tokens[1]) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to cd: %s\n", strerror(errno)); - exit(EXIT_FAILURE); + if (chdir(tokens[1]) == -1) + warn("Unable to change directory to `%s'", tokens[1]); + } else if (strcmp(tokens[0], "fg") == 0) { // TODO: Take an argument + if ((fgpgid = popbgps()) == -1) { + warnx("No background processes"); + return 1; } - } else if (strcmp(tokens[0], "fg") == 0) { - if ((fgpgid = popbgps()) == -1) return 1; if (tcsetpgrp(STDIN_FILENO, fgpgid) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to set tty foreground " - "process group: %s\n", strerror(errno)); - exit(EXIT_FAILURE); + warn("Unable to bring process group %d to foreground", fgpgid); + return 1; } if (killpg(fgpgid, SIGCONT) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to wake up process group " - "%d to wake up: %s\n", fgpgid, strerror(errno)); - exit(EXIT_FAILURE); + if (tcsetpgrp(STDIN_FILENO, self) == -1) exit(EXIT_FAILURE); + warn("Unable to wake up process group %d", fgpgid); + return 1; } await(fgpgid); } else return 0; @@ -120,44 +98,45 @@ int main(void) { char **tokens; pid_t cpgid; - signal(SIGINT, nlprompt); + signal(SIGINT, prompt); + if ((self = getpgid(0)) == -1) + err(EXIT_FAILURE, "Unable to get pgid of self"); for (;;) { - printf("%% "); + prompt(0); if (fgets(buffer, BUFLEN, stdin) == NULL) { if (feof(stdin)) { printf("\n"); exit(EXIT_SUCCESS); } - dprintf(STDERR_FILENO, "ash: Couldn't read input"); - if (!ferror(stdin)) dprintf(STDERR_FILENO, ": %s", strerror(errno)); - dprintf(STDERR_FILENO, "\n"); - exit(EXIT_FAILURE); + warn("Unable to read user input"); + continue; } tokens = tokenize(buffer); - if (builtin(tokens)) continue; + if (!*tokens || builtin(tokens)) continue; - if ((cpgid = fork()) == 0) { - if (execvp(tokens[0], tokens) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to run command `%s': %s\n", - tokens[0], strerror(errno)); - exit(EXIT_FAILURE); - } - } + if ((cpgid = fork()) == 0) + if (execvp(tokens[0], tokens) == -1) + err(EXIT_FAILURE, "Unable to run command `%s'", tokens[0]); if (setpgid(cpgid, cpgid) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to change child group process id: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); + warn("Unable to set process group of process %d", cpgid); + if (kill(cpgid, SIGKILL) == -1) + warn("Unable to kill process %d; manual termination required", cpgid); + continue; } if (tcsetpgrp(STDIN_FILENO, cpgid) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to set tty foreground " - "process group: %s\n", strerror(errno)); - exit(EXIT_FAILURE); + warn("Unable to bring process group %d to foreground", cpgid); + if (killpg(cpgid, SIGKILL) == -1) + warn("Unable to kill process group %d; manual termination required", cpgid); + continue; } if (killpg(cpgid, SIGCONT) == -1) { - dprintf(STDERR_FILENO, "ash: Unable to signal child to wake up: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); + if (tcsetpgrp(STDIN_FILENO, self) == -1) exit(EXIT_FAILURE); + warn("Process group %d may be blocked; killing it", cpgid); + if (killpg(cpgid, SIGKILL) == -1) + warn("Unable to kill process group %d; manual termination required", cpgid); + else warn("Successfully terminated process group %d", cpgid); + continue; } await(cpgid); } -- 2.51.0