From a1b8a7a09230e8be9d7aedf12291a434478b2f02 Mon Sep 17 00:00:00 2001 From: Trent Huber Date: Fri, 22 Aug 2025 14:11:37 -0400 Subject: [PATCH] Linux compatibility checkin, more bug fixes --- src/build.c | 1 - src/builtin/alias.c | 2 +- src/builtin/bg.c | 133 +++++++++++++++++++++++++++++++++++++----- src/builtin/bg.h | 19 ++++++ src/builtin/builtin.c | 2 +- src/builtin/fg.c | 108 ++++++++++++++++++---------------- src/builtin/fg.h | 5 +- src/builtin/source.c | 5 +- src/builtin/which.c | 4 +- src/context.c | 2 +- src/history.c | 6 +- src/history.h | 2 +- src/input.c | 85 ++++++++++++++++++--------- src/input.h | 16 ----- src/job.c | 88 ---------------------------- src/job.h | 13 ----- src/parse.c | 15 +++-- src/run.c | 47 +++++++-------- src/utils.c | 9 ++- 19 files changed, 301 insertions(+), 261 deletions(-) create mode 100644 src/builtin/bg.h delete mode 100644 src/job.c delete mode 100644 src/job.h diff --git a/src/build.c b/src/build.c index 8e76274..07a1eac 100644 --- a/src/build.c +++ b/src/build.c @@ -13,7 +13,6 @@ int main(void) { {"context", NONE}, {"history", NONE}, {"input", NONE}, - {"job", NONE}, {"main", BUILTINS}, {"options", BUILTINS}, {"parse", BUILTINS}, diff --git a/src/builtin/alias.c b/src/builtin/alias.c index a4c5d6d..a208a86 100644 --- a/src/builtin/alias.c +++ b/src/builtin/alias.c @@ -52,7 +52,7 @@ BUILTIN(alias) { switch (argc) { case 1: for (i = 0; i < aliases.size; ++i) - printf("%s = \"%s\"\r\n", aliases.entries[i].lhs, aliases.entries[i].rhs); + printf("%s = \"%s\"\n", aliases.entries[i].lhs, aliases.entries[i].rhs); break; case 3: if (aliases.size == MAXALIAS) { diff --git a/src/builtin/bg.c b/src/builtin/bg.c index 55232ec..15457b0 100644 --- a/src/builtin/bg.c +++ b/src/builtin/bg.c @@ -1,21 +1,128 @@ #include #include #include +#include #include #include +#include "bg.h" #include "builtin.h" -#include "job.h" +#include "fg.h" #include "utils.h" +#define MAXBG 100 + +struct bglink { + struct bgjob job; + struct bglink *next; +}; + +static struct { + struct bglink entries[MAXBG + 1], *active, *free; +} bgjobs; + +void initbg(void) { + size_t i; + + for (i = 0; i < MAXBG - 1; ++i) + bgjobs.entries[i].next = &bgjobs.entries[i + 1]; + bgjobs.free = bgjobs.entries; +} + +int fullbg(void) { + return !bgjobs.free; +} + +int pushbg(struct bgjob job) { + struct bglink *p; + + if (fullbg()) return 0; + + (p = bgjobs.free)->job = job; + bgjobs.free = p->next; + p->next = bgjobs.active; + bgjobs.active = p; + + return 1; +} + +int peekbg(struct bgjob *job) { + if (bgjobs.active && job) *job = bgjobs.active->job; + return bgjobs.active != NULL; +} + +int searchbg(pid_t id, struct bgjob *job) { + struct bglink *p; + + for (p = bgjobs.active; p; p = p->next) if (p->job.id == id) { + if (job) *job = p->job; + return 1; + } + + return 0; +} + +int pushid(pid_t id) { + return pushbg((struct bgjob){.id = id, .config = canonical}); +} + +void removeid(pid_t id) { + struct bglink *p, *prev; + + for (prev = NULL, p = bgjobs.active; p; prev = p, p = p->next) + if (p->job.id == id) break; + if (!p) return; + + if (prev) prev->next = p->next; else bgjobs.active = p->next; + p->next = bgjobs.free; + bgjobs.free = p; +} + +void waitbg(int sig) { + int e, s; + struct bglink *p; + pid_t id; + + (void)sig; + e = errno; + p = bgjobs.active; + while (p) { + while ((id = waitpid(-p->job.id, &s, WNOHANG | WUNTRACED)) > 0) { + if (WIFSTOPPED(s)) { + p->job.suspended = 1; + break; + } + } + if (id == -1) { + id = p->job.id; + p = p->next; + removeid(id); + } else p = p->next; + } + errno = e; +} + +void deinitbg(void) { + struct bglink *p; + + for (p = bgjobs.active; p; p = p->next) killpg(p->job.id, SIGKILL); +} + BUILTIN(bg) { + struct bglink *p; + struct bgjob job; long l; - pid_t id; - struct job *job; switch (argc) { case 1: - if (!(job = peeksuspendedjob())) return EXIT_FAILURE; + for (p = bgjobs.active; p; p = p->next) if (p->job.suspended) { + job = p->job; + break; + } + if (!p) { + note("No suspended jobs to run in the background"); + return EXIT_FAILURE; + } break; case 2: errno = 0; @@ -23,26 +130,26 @@ BUILTIN(bg) { note("Invalid job id %ld", l); return EXIT_FAILURE; } - if (!(job = searchjobid(id = (pid_t)l))) { - note("Unable to find job %d", id); + if (!searchbg(l, &job)) { + note("Unable to find job %d", (pid_t)l); return EXIT_FAILURE; } - if (!job->suspended) { - note("Job %d already in background", id); + if (!job.suspended) { + note("Job %d already in background", job.id); return EXIT_FAILURE; } break; default: return usage(argv[0], "[pgid]"); } - deletejobid(job->id); - if (!pushjob(job)) return EXIT_FAILURE; - if (killpg(job->id, SIGCONT) == -1) { - note("Unable to wake up suspended job %d", job->id); + if (killpg(job.id, SIGCONT) == -1) { + note("Unable to wake up suspended job %d", job.id); return EXIT_FAILURE; } - job->suspended = 0; + removeid(job.id); + job.suspended = 0; + pushbg(job); return EXIT_SUCCESS; } diff --git a/src/builtin/bg.h b/src/builtin/bg.h new file mode 100644 index 0000000..6b6c135 --- /dev/null +++ b/src/builtin/bg.h @@ -0,0 +1,19 @@ +struct bgjob { + pid_t id; + struct termios config; + int suspended; +}; + +void initbg(void); + +int fullbg(void); +int pushbg(struct bgjob job); +int peekbg(struct bgjob *job); +int searchbg(pid_t id, struct bgjob *job); + +int pushid(pid_t id); +void removeid(pid_t id); + +void waitbg(int sig); + +void deinitbg(void); diff --git a/src/builtin/builtin.c b/src/builtin/builtin.c index 7a2831c..d9ef4d1 100644 --- a/src/builtin/builtin.c +++ b/src/builtin/builtin.c @@ -20,6 +20,6 @@ int isbuiltin(char **args) { } int usage(char *program, char *options) { - fprintf(stderr, "Usage: %s %s\r\n", program, options); + fprintf(stderr, "Usage: %s %s\n", program, options); return EXIT_FAILURE; } diff --git a/src/builtin/fg.c b/src/builtin/fg.c index 1335957..15fb381 100644 --- a/src/builtin/fg.c +++ b/src/builtin/fg.c @@ -3,20 +3,24 @@ #include #include #include +#include #include #include +#include "bg.h" #include "builtin.h" -#include "job.h" +#include "context.h" +#include "input.h" #include "utils.h" static struct { pid_t id; int status, done; -} fgpg; +} fgjob; struct termios canonical; static struct termios raw; -struct sigaction sigchld, sigdfl; +struct sigaction actbg, actdefault; +static struct sigaction actall, actignore; static int setconfig(struct termios *mode) { if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) { @@ -26,22 +30,21 @@ static int setconfig(struct termios *mode) { return 1; } -static void sigchldhandler(int sig) { - int e; +static void waitall(int sig) { + int e, s; pid_t id; - struct job *job; - (void)sig; e = errno; - while ((id = waitpid(-1, &fgpg.status, WNOHANG | WUNTRACED)) > 0) - if ((job = searchjobid(id))) { - if (WIFSTOPPED(fgpg.status)) job->suspended = 1; else deletejobid(id); - } else { - fgpg.done = 1; - if (WIFSTOPPED(fgpg.status)) continue; - if (id != fgpg.id) waitpid(fgpg.id, &fgpg.status, 0); - while (waitpid(-fgpg.id, NULL, 0) != -1); + while ((id = waitpid(-fgjob.id, &s, WNOHANG | WUNTRACED)) > 0) { + if (id == fgjob.id) fgjob.status = s; + if (WIFSTOPPED(s)) { + fgjob.status = s; + fgjob.done = 1; + break; } + } + if (id == -1) fgjob.done = 1; + waitbg(sig); errno = e; } @@ -53,62 +56,65 @@ void setsigchld(struct sigaction *act) { void initfg(void) { if (tcgetattr(STDIN_FILENO, &canonical) == -1) fatal("Unable to get default termios config"); - cfmakeraw(&raw); + raw = canonical; + raw.c_lflag &= ~(ICANON | ECHO | ISIG); if (!setconfig(&raw)) exit(EXIT_FAILURE); - sigchld.sa_handler = sigchldhandler; - sigdfl.sa_handler = SIG_DFL; - setsigchld(&sigchld); + actbg.sa_handler = waitbg; + actall.sa_handler = waitall; + actdefault.sa_handler = SIG_DFL; + actignore.sa_handler = SIG_IGN; } -int setfg(struct job job) { +int runfg(pid_t id) { + struct bgjob job; + + if (!searchbg(id, &job)) job = (struct bgjob){.id = id, .config = canonical}; if (!setconfig(&job.config)) return 0; - if (tcsetpgrp(STDIN_FILENO, job.id) == -1) { - note("Unable to bring job %d to foreground", job.id); + if (tcsetpgrp(STDIN_FILENO, id) == -1) { + note("Unable to bring job %d to foreground", id); setconfig(&raw); return 0; } - if (killpg(job.id, SIGCONT) == -1) { - note("Unable to wake up job %d", job.id); + if (killpg(id, SIGCONT) == -1) { + note("Unable to wake up job %d", id); return 0; } - return 1; -} - -void waitfg(struct job job) { - struct sigaction sigign; + removeid(id); /* SIGCHLD handler is really the function that reaps the foreground process, * the waitpid() below is just to block the current thread of execution until * the foreground process has been reaped. */ - fgpg.id = job.id; - setsigchld(&sigchld); - while (waitpid(fgpg.id, NULL, 0) && !fgpg.done); - fgpg.done = errno = 0; - setsigchld(&sigdfl); + fgjob.id = id; + setsigchld(&actall); + while (!fgjob.done) sigsuspend(&actall.sa_mask); + setsigchld(&actdefault); + fgjob.done = errno = 0; - if (sigaction(SIGTTOU, &(struct sigaction){{SIG_IGN}}, NULL) == -1 + if (sigaction(SIGTTOU, &actignore, NULL) == -1 || tcsetpgrp(STDIN_FILENO, getpgrp()) == -1 - || sigaction(SIGTTOU, &sigdfl, NULL) == -1) { + || sigaction(SIGTTOU, &actdefault, NULL) == -1) { note("Unable to reclaim foreground; terminating"); deinit(); exit(EXIT_FAILURE); } if (tcgetattr(STDIN_FILENO, &job.config) == -1) - note("Unable to save termios config of job %d", job.id); + note("Unable to save termios config of job %d", id); setconfig(&raw); - if (WIFEXITED(fgpg.status)) status = WEXITSTATUS(fgpg.status); - else if (WIFSTOPPED(fgpg.status)) { - status = WSTOPSIG(fgpg.status); + if (WIFEXITED(fgjob.status)) status = WEXITSTATUS(fgjob.status); + else if (WIFSTOPPED(fgjob.status)) { + status = WSTOPSIG(fgjob.status); job.suspended = 1; - if (!pushjob(&job)) { - note("Press any key to continue"); + if (!pushbg(job)) { + note("Unable to suspend current process, too many background jobs\n" + "(Press any key to continue)"); getchar(); - if (setfg(job)) return waitfg(job); - note("Manual intervention required for job %d", job.id); + return runfg(id); } - } else status = WTERMSIG(fgpg.status); + } else status = WTERMSIG(fgjob.status); + + return 1; } void deinitfg(void) { @@ -116,16 +122,17 @@ void deinitfg(void) { } BUILTIN(fg) { + struct bgjob job; long l; pid_t id; - struct job *job; switch (argc) { case 1: - if (!(job = pulljob())) { + if (!peekbg(&job)) { note("No job to bring into the foreground"); return EXIT_FAILURE; } + id = job.id; break; case 2: errno = 0; @@ -133,18 +140,17 @@ BUILTIN(fg) { note("Invalid process group id %ld", l); return EXIT_FAILURE; } - if (!(job = searchjobid(id))) { + id = (pid_t)l; + if (!searchbg(id, NULL)) { note("Unable to find job %d", id); return EXIT_FAILURE; } - deletejobid(id); break; default: return usage(argv[0], "[pgid]"); } - if (!setfg(*job)) return EXIT_FAILURE; - waitfg(*job); + if (!runfg(id)) return EXIT_FAILURE; return EXIT_SUCCESS; } diff --git a/src/builtin/fg.h b/src/builtin/fg.h index dd98ff5..6436bc4 100644 --- a/src/builtin/fg.h +++ b/src/builtin/fg.h @@ -1,8 +1,7 @@ extern struct termios canonical; -extern struct sigaction sigchld, sigdfl; +extern struct sigaction actbg, actdefault; void setsigchld(struct sigaction *act); void initfg(void); -int setfg(struct job job); -void waitfg(struct job job); +int runfg(pid_t id); void deinitfg(void); diff --git a/src/builtin/source.c b/src/builtin/source.c index c53c09c..91f0570 100644 --- a/src/builtin/source.c +++ b/src/builtin/source.c @@ -14,10 +14,7 @@ BUILTIN(source) { int c; char **v; - if (argc == 1) { - fputs("Usage: source file [args ...]\r\n", stderr); - return EXIT_FAILURE; - } + if (argc == 1) return usage(argv[0], "file [args ...]"); context = (struct context){0}; context.script = argv[1]; diff --git a/src/builtin/which.c b/src/builtin/which.c index 6b3d6a5..2cde228 100644 --- a/src/builtin/which.c +++ b/src/builtin/which.c @@ -83,13 +83,13 @@ BUILTIN(which) { if (argc != 2) return usage(argv[0], "name"); if (!(result = getpathtype(argv[1], &type))) { - printf("%s not found\r\n", argv[1]); + printf("%s not found\n", argv[1]); return EXIT_SUCCESS; } fputs(result, stdout); if (type == BUILTIN) fputs(" is built-in", stdout); - puts("\r"); + putchar('\n'); return EXIT_SUCCESS; } diff --git a/src/context.c b/src/context.c index e11ec3c..35f9b61 100644 --- a/src/context.c +++ b/src/context.c @@ -7,7 +7,7 @@ int clear(struct context *c) { c->b = NULL; c->t = NULL; c->r = NULL; - *c->current.name = '\0'; + *c->current.name = *c->buffer = '\0'; c->current.term = SEMI; return 1; diff --git a/src/history.c b/src/history.c index 945064d..511ce7a 100644 --- a/src/history.c +++ b/src/history.c @@ -35,14 +35,14 @@ void inithistory(void) { if (fclose(file) == EOF) fatal("Unable to close history file"); } -int gethistory(char direction, char *buffer) { - if (history.c == (direction == UP ? history.b : history.t)) return 0; +int gethistory(int back, char *buffer) { + if (history.c == (back ? history.b : history.t)) return 0; // Save the most recently modified history entry at the top of the list if (strcmp(history.entries[history.c], buffer) != 0) strcpy(history.entries[history.t], buffer); - strcpy(buffer, history.entries[direction == UP ? DEC(c) : INC(c)]); + strcpy(buffer, history.entries[back ? DEC(c) : INC(c)]); return 1; } diff --git a/src/history.h b/src/history.h index 4c2428d..49dce14 100644 --- a/src/history.h +++ b/src/history.h @@ -1,4 +1,4 @@ void inithistory(void); -int gethistory(char direction, char *buffer); +int gethistory(int back, char *buffer); void sethistory(char *buffer); void deinithistory(void); diff --git a/src/input.c b/src/input.c index b73b69b..9e6622f 100644 --- a/src/input.c +++ b/src/input.c @@ -12,6 +12,24 @@ #include "input.h" #include "utils.h" +enum { + CTRLC = '\003', + CTRLD, + CLEAR = '\014', + ESCAPE = '\033', + + // See ESCAPE case in userinput() + ALT = '2' + 1, + + UP = 'A', + DOWN, + RIGHT, + LEFT, + FORWARD = 'f', + BACKWARD = 'b', + DEL = '\177', +}; + int stringinput(struct context *c) { char *start; size_t l; @@ -72,23 +90,22 @@ static void prompt(void) { if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = ">", 1) == -1) note("Unable to update $PROMPT$ environment variable"); - printf("\r%s ", p); + printf("%s ", p); } int userinput(struct context *c) { char *start, *cursor, *end; - unsigned int current; - int i; + int current, i; size_t oldlen, newlen; + clear(c); end = cursor = start = c->buffer; - *c->buffer = '\0'; while (start == end) { prompt(); - while ((current = getchar()) != '\r') switch (current) { + while ((current = getchar()) != '\n') switch (current) { default: if (current >= ' ' && current <= '~') { - if (end - start == MAXCHARS) continue; + if (end - start == MAXCHARS) break; memmove(cursor + 1, cursor, end - cursor); *cursor++ = current; *++end = '\0'; @@ -99,32 +116,41 @@ int userinput(struct context *c) { } break; case CTRLC: - puts("^C\r"); + puts("^C"); return quit(c); case CTRLD: - puts("^D\r"); + puts("^D"); return 0; case CLEAR: fputs("\033[H\033[J", stdout); prompt(); fputs(c->buffer, stdout); - continue; + break; + + /* This is a very minimal way to handle arrow keys. All modifiers except for + * the ALT key are processed but ignored. + * + * Reference: + * https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_input_sequences */ case ESCAPE: - switch ((current = getchar())) { - case FORWARD: - while (cursor != end && *cursor != ' ') putchar(*cursor++); - while (cursor != end && *cursor == ' ') putchar(*cursor++); - break; - case BACKWARD: - while (cursor != start && *(cursor - 1) == ' ') putchar((--cursor, '\b')); - while (cursor != start && *(cursor - 1) != ' ') putchar((--cursor, '\b')); - break; - case ARROW: - switch ((current = getchar())) { + if ((current = getchar()) == '[') { + while ((current = getchar()) >= '0' && current <= '9'); + if (current == ';') { + if ((current = getchar()) == ALT) switch ((current = getchar())) { + case LEFT: + current = BACKWARD; + break; + case RIGHT: + current = FORWARD; + break; + } else if ((current = getchar()) >= '0' && current <= '6') + current = getchar(); + } + switch (current) { case UP: case DOWN: oldlen = strlen(c->buffer); - if (!gethistory(current, c->buffer)) continue; + if (!gethistory(current == UP, c->buffer)) break; newlen = strlen(c->buffer); end = cursor = start + newlen; @@ -142,14 +168,21 @@ int userinput(struct context *c) { if (cursor < end) putchar(*cursor++); break; } + } + switch (current) { + case FORWARD: + while (cursor != end && *cursor != ' ') putchar(*cursor++); + while (cursor != end && *cursor == ' ') putchar(*cursor++); + break; + case BACKWARD: + while (cursor != start && *(cursor - 1) == ' ') putchar((--cursor, '\b')); + while (cursor != start && *(cursor - 1) != ' ') putchar((--cursor, '\b')); break; - default: - ungetc(current, stdin); } break; - case BACKSPACE: + case DEL: - if (cursor == start) continue; + if (cursor == start) break; memmove(cursor - 1, cursor, end - cursor); --cursor; *--end = '\0'; @@ -161,7 +194,7 @@ int userinput(struct context *c) { break; } - puts("\r"); + putchar('\n'); } while (*start == ' ') ++start; diff --git a/src/input.h b/src/input.h index 3762b05..ba55688 100644 --- a/src/input.h +++ b/src/input.h @@ -1,19 +1,3 @@ -enum { - CTRLC = '\003', - CTRLD, - BACKSPACE = '\010', - CLEAR = '\014', - ESCAPE = '\033', - FORWARD = 'f', - BACKWARD = 'b', - ARROW = '[', - UP = 'A', - DOWN, - RIGHT, - LEFT, - DEL = '\177', -}; - int stringinput(struct context *c); int scriptinput(struct context *c); int userinput(struct context *c); diff --git a/src/job.c b/src/job.c deleted file mode 100644 index c412040..0000000 --- a/src/job.c +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include - -#include "job.h" -#include "utils.h" - -#define MAXJOBS 100 - -struct joblink { - struct job job; - struct joblink *next; -}; - -static struct { - struct joblink entries[MAXJOBS + 1], *active, *free; -} jobs; - -void initjobs(void) { - size_t i; - - for (i = 0; i < MAXJOBS - 1; ++i) jobs.entries[i].next = &jobs.entries[i + 1]; - jobs.free = jobs.entries; -} - -struct job *pushjob(struct job *job) { - struct joblink *p; - - if (!jobs.free) { - note("Unable to %s, exceeds %d job limit", - job->suspended ? "suspend job" : "place job in background", MAXJOBS); - return NULL; - } - - (p = jobs.free)->job = *job; - jobs.free = p->next; - p->next = jobs.active; - jobs.active = p; - - return &p->job; -} - -struct job *pulljob(void) { - struct joblink *p; - - if (!jobs.active) return NULL; - - p = jobs.active; - jobs.active = p->next; - p->next = jobs.free; - jobs.free = p; - - return &p->job; -} - -struct job *peekjob(void) { - return jobs.active ? &jobs.active->job : NULL; -} - -struct job *peeksuspendedjob(void) { - struct joblink *p; - - for (p = jobs.active; p; p = p->next) if (p->job.suspended) return &p->job; - - note("No suspended job to run in background"); - - return NULL; -} - -struct job *searchjobid(pid_t id) { - struct joblink *p; - - for (p = jobs.active; p; p = p->next) if (p->job.id == id) return &p->job; - - return NULL; -} - -struct job *deletejobid(pid_t id) { - struct joblink *p, *prev; - - for (prev = NULL, p = jobs.active; p; prev = p, p = p->next) if (p->job.id == id) break; - if (!p) return NULL; - - if (prev) prev->next = p->next; else jobs.active = p->next; - p->next = jobs.free; - jobs.free = p; - - return &p->job; -} diff --git a/src/job.h b/src/job.h deleted file mode 100644 index 28a4673..0000000 --- a/src/job.h +++ /dev/null @@ -1,13 +0,0 @@ -struct job { - pid_t id; - struct termios config; - int suspended; -}; - -void initjobs(void); -struct job *pushjob(struct job *job); -struct job *pulljob(void); -struct job *peekjob(void); -struct job *peeksuspendedjob(void); -struct job *searchjobid(pid_t id); -struct job *deletejobid(pid_t id); diff --git a/src/parse.c b/src/parse.c index 2ef49b4..65e1308 100644 --- a/src/parse.c +++ b/src/parse.c @@ -11,10 +11,10 @@ #include "utils.h" int parse(struct context *c) { - int globbing, e, offset; + int globbing, e, offset, globflags; + size_t prevsublen, sublen; char *stlend, *p, *end, *env, term, **sub; long l; - size_t sublen; static glob_t globs; if (!c->b) { @@ -29,7 +29,7 @@ int parse(struct context *c) { c->r = c->redirects; c->r->mode = NONE; c->prev = c->current; - globbing = 0; + prevsublen = globbing = 0; for (*c->t = c->b; *c->b; ++c->b) switch (*c->b) { case '<': @@ -164,15 +164,18 @@ int parse(struct context *c) { *c->t = c->b; } else if (!c->alias && c->t == c->tokens && (sub = getalias(*c->tokens)) || globbing) { if (globbing) { - switch (glob(*c->t, GLOB_APPEND | GLOB_MARK, NULL, &globs)) { + globflags = GLOB_MARK; + if (prevsublen) globflags |= GLOB_APPEND; + switch (glob(*c->t, globflags, NULL, &globs)) { case GLOB_NOMATCH: note("No matches found for %s", *c->t); return quit(c); case GLOB_NOSPACE: fatal("Memory allocation"); } - sublen = globs.gl_matchc; - sub = globs.gl_pathv + globs.gl_pathc - sublen; + sublen = globs.gl_pathc - prevsublen; + sub = globs.gl_pathv + prevsublen; + prevsublen = globs.gl_pathc; globbing = 0; } else for (sublen = 0; sub[sublen]; ++sublen); diff --git a/src/run.c b/src/run.c index 6fa314c..a367511 100644 --- a/src/run.c +++ b/src/run.c @@ -7,10 +7,11 @@ #include #include #include +#include // XXX #include "builtin.h" #include "context.h" -#include "job.h" +#include "bg.h" #include "fg.h" #include "parse.h" #include "utils.h" @@ -73,17 +74,23 @@ int run(struct context *c) { int islist, ispipe, ispipestart, ispipeend; char *path; pid_t cpid, jobid; - struct job *p, job; + static pid_t pipeid; - setsigchld(&sigchld); + setsigchld(&actbg); if (!parse(c)) return 0; - setsigchld(&sigdfl); - + setsigchld(&actdefault); islist = c->prev.term > BG || c->current.term > BG; if (c->t) { + if (c->current.term == BG && fullbg()) { + note("Unable to place job in background, too many background jobs", + c->current.name); + return quit(c); + } if (!(path = getpath(c->current.name))) { note("Couldn't find `%s' command", c->current.name); - if (c->prev.term == PIPE) closepipe(c->prev); + if (c->prev.term == PIPE) { + killpg(pipeid, SIGKILL); + } return quit(c); } @@ -97,7 +104,7 @@ int run(struct context *c) { if (!ispipestart) closepipe(c->prev); return quit(c); } - if ((jobid = cpid = fork()) == -1) { + if ((cpid = fork()) == -1) { note("Unable to fork child process"); return quit(c); } else if (cpid == 0) { @@ -113,15 +120,8 @@ int run(struct context *c) { } exec(path, c); } - if (!ispipestart) { - closepipe(c->prev); - if (!(p = (ispipeend ? pulljob : peekjob)())) { - note("Unable to %s pipeline job from background", - ispipeend ? "remove" : "get"); - return quit(c); - } - jobid = p->id; - } + if (ispipestart) pipeid = cpid; + jobid = pipeid; } else if (!c->r && isbuiltin(c->tokens)) cpid = 0; else if ((jobid = cpid = fork()) == -1) { note("Unable to fork child process"); @@ -137,16 +137,11 @@ int run(struct context *c) { } return quit(c); } - job = (struct job){.id = jobid, .config = canonical}; if (ispipestart || c->current.term == BG) { - if (!pushjob(&job)) { - if (ispipestart) closepipe(c->current); - return quit(c); - } - } else if (c->current.term != PIPE) { - if (!setfg(job)) return quit(c); - waitfg(job); + pushid(jobid); + return 1; } + if (c->current.term != PIPE && !runfg(jobid)) return quit(c); } if (status != EXIT_SUCCESS) { @@ -155,11 +150,11 @@ int run(struct context *c) { } else if (c->current.term == OR) return clear(c); } else { if (islist) { - if (c->prev.term == PIPE) closepipe(c->prev); + if (c->prev.term == PIPE) killpg(pipeid, SIGKILL); note("Expected command"); return quit(c); } - if (c->r) return 1; + if (!c->r) return 1; if ((cpid = fork()) == -1) { note("Unable to fork child process"); diff --git a/src/utils.c b/src/utils.c index e0ff12a..d02330e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -8,10 +8,10 @@ #include #include +#include "bg.h" #include "context.h" -#include "history.h" -#include "job.h" #include "fg.h" +#include "history.h" #include "options.h" int argcount, status; @@ -22,7 +22,6 @@ void note(char *fmt, ...) { va_start(args, fmt); (errno ? vwarn : vwarnx)(fmt, args); va_end(args); - putc('\r', stderr); errno = 0; } @@ -31,7 +30,6 @@ void fatal(char *fmt, ...) { va_start(args, fmt); (errno ? vwarn : vwarnx)(fmt, args); va_end(args); - putc('\r', stderr); exit(EXIT_FAILURE); } @@ -62,7 +60,7 @@ void init(void) { note("Unable to update $SHLVL$ environment variable"); initfg(); - initjobs(); + initbg(); if (interactive) inithistory(); } @@ -84,5 +82,6 @@ char *catpath(char *dir, char *filename, char *buffer) { void deinit(void) { if (interactive) deinithistory(); + deinitbg(); deinitfg(); } -- 2.51.0