From 3456cf1b471b194a2514809d258255cb4390991b Mon Sep 17 00:00:00 2001 From: Trent Huber Date: Mon, 11 Aug 2025 22:45:32 -0400 Subject: [PATCH] Memory optimization for file redirect structs, clean up code --- src/builtin/alias.c | 25 +++++----- src/builtin/alias.h | 2 +- src/builtin/build.c | 12 +++-- src/builtin/fg.c | 21 ++++---- src/builtin/fg.h | 6 +-- src/builtin/source.c | 2 +- src/context.h | 37 ++++++++------ src/history.c | 9 ++-- src/history.h | 4 +- src/input.c | 52 +++++++++++-------- src/input.h | 10 ++-- src/job.c | 23 +++++---- src/job.h | 4 +- src/main.c | 8 +-- src/options.c | 9 ++-- src/parse.c | 78 +++++++++++++++++------------ src/parse.h | 2 +- src/run.c | 115 +++++++++++++++++++++++-------------------- src/run.h | 2 +- src/utils.c | 22 ++++----- src/utils.h | 4 +- 21 files changed, 244 insertions(+), 203 deletions(-) diff --git a/src/builtin/alias.c b/src/builtin/alias.c index 22d5723..49c9100 100644 --- a/src/builtin/alias.c +++ b/src/builtin/alias.c @@ -3,8 +3,8 @@ #include #include "builtin.h" -#include "input.h" #include "context.h" +#include "input.h" #include "parse.h" #include "utils.h" @@ -18,22 +18,22 @@ static struct { size_t size; } aliases; -void applyaliases(struct cmd *cmd) { - struct cmd *p; +void applyaliases(struct command *command) { + struct command *c; char **end; size_t i, l, a; struct context *context; - p = cmd; + c = command; - end = p->args; - while ((p = p->next)) if (p->args) end = p->args; + end = c->args; + while ((c = c->next)) if (c->args) end = c->args; if (end) while (*end) ++end; - while ((p = cmd = cmd->next)) { - if (!cmd->args) continue; + while ((c = command = command->next)) { + if (!command->args) continue; for (i = 0; i < aliases.size; ++i) - if (strcmp(aliases.entries[i].lhs, *cmd->args) == 0) break; + if (strcmp(aliases.entries[i].lhs, *command->args) == 0) break; if (i == aliases.size) continue; context = &aliases.entries[i].context; @@ -45,9 +45,10 @@ void applyaliases(struct cmd *cmd) { parse(context); for (a = 0; context->tokens[a]; ++a); - memmove(cmd->args + a, cmd->args + 1, (end - cmd->args + 1) * sizeof*cmd->args); - memcpy(cmd->args, context->tokens, a * sizeof*cmd->args); - while ((p = p->next)) p->args += a - 1; + memmove(command->args + a, command->args + 1, + (end - command->args + 1) * sizeof*command->args); + memcpy(command->args, context->tokens, a * sizeof*command->args); + while ((c = c->next)) c->args += a - 1; } } diff --git a/src/builtin/alias.h b/src/builtin/alias.h index 02b4643..b84318f 100644 --- a/src/builtin/alias.h +++ b/src/builtin/alias.h @@ -1 +1 @@ -void applyaliases(struct cmd *cmd); +void applyaliases(struct command *command); diff --git a/src/builtin/build.c b/src/builtin/build.c index 9f52650..9a5c843 100644 --- a/src/builtin/build.c +++ b/src/builtin/build.c @@ -13,7 +13,13 @@ int main(void) { int listfd, l; DIR *dir; size_t i, offset; - struct cbsfile files[1 + MAXBUILTINS + 1]; + + /* The three extra files correspond to: + * 1) output file (../libbuiltin.a) + * 2) list.c + * 3) builtin.c */ + struct cbsfile files[3 + MAXBUILTINS + 1]; + struct dirent *entry; char *name, *identifier; @@ -35,7 +41,7 @@ int main(void) { if (strcmp(entry->d_name, "build.c") == 0) continue; if (!(name = strrchr(entry->d_name, '.')) || strcmp(name, ".c") != 0) continue; - if (i == 1 + MAXBUILTINS + 1) + if (i == 3 + MAXBUILTINS + 1) errx(EXIT_FAILURE, "Unable to add built-in `%s', maximum reached (%d)", name, MAXBUILTINS); if (!(name = strdup(entry->d_name))) @@ -48,7 +54,7 @@ int main(void) { } if (errno) err(EXIT_FAILURE, "Unable to read from current directory"); files[i] = (struct cbsfile){NULL}; - + identifier = "struct builtin builtins[] = {"; l = (int)strlen(identifier); dprintf(listfd, "\n%s", identifier); diff --git a/src/builtin/fg.c b/src/builtin/fg.c index c471f46..cdff59b 100644 --- a/src/builtin/fg.c +++ b/src/builtin/fg.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -12,8 +11,9 @@ #include "utils.h" static int fgstatus; +struct termios canonical; +static struct termios raw; struct sigaction sigchld, sigdfl; -struct termios raw, canonical; static int setconfig(struct termios *mode) { if (tcsetattr(STDIN_FILENO, TCSANOW, mode) == -1) { @@ -39,9 +39,9 @@ void setsigchld(struct sigaction *act) { fatal("Unable to install SIGCHLD handler"); } -void initterm(void) { +void initfg(void) { if (tcgetattr(STDIN_FILENO, &canonical) == -1) - err(EXIT_FAILURE, "Unable to get default termios config"); + fatal("Unable to get default termios config"); cfmakeraw(&raw); if (!setconfig(&raw)) exit(EXIT_FAILURE); @@ -71,15 +71,15 @@ void waitfg(struct job job) { * the waitpid() below is just to block the current thread of execution until * the foreground process has been reaped */ setsigchld(&sigchld); - while (waitpid(job.id, NULL, 0) != -1); - errno = 0; + waitpid(job.id, NULL, 0); + errno = 0; // waitpid() will set errno setsigchld(&sigdfl); if (sigaction(SIGTTOU, &(struct sigaction){{SIG_IGN}}, NULL) == -1 || tcsetpgrp(STDIN_FILENO, getpgrp()) == -1 || sigaction(SIGTTOU, &sigdfl, NULL) == -1) { note("Unable to reclaim foreground; terminating"); - deinitialize(); + deinit(); exit(EXIT_FAILURE); } if (tcgetattr(STDIN_FILENO, &job.config) == -1) @@ -101,7 +101,7 @@ void waitfg(struct job job) { } } -void deinitterm(void) { +void deinitfg(void) { setconfig(&canonical); } @@ -126,5 +126,8 @@ BUILTINSIG(fg) { return EXIT_FAILURE; } - return setfg(*job) ? (waitfg(*job), EXIT_SUCCESS) : EXIT_FAILURE; + if (!setfg(*job)) return EXIT_FAILURE; + waitfg(*job); + + return EXIT_SUCCESS; } diff --git a/src/builtin/fg.h b/src/builtin/fg.h index da4eff7..dd98ff5 100644 --- a/src/builtin/fg.h +++ b/src/builtin/fg.h @@ -1,8 +1,8 @@ +extern struct termios canonical; extern struct sigaction sigchld, sigdfl; -extern struct termios raw, canonical; void setsigchld(struct sigaction *act); -void initterm(void); +void initfg(void); int setfg(struct job job); void waitfg(struct job job); -void deinitterm(void); +void deinitfg(void); diff --git a/src/builtin/source.c b/src/builtin/source.c index 90f15cc..7190f84 100644 --- a/src/builtin/source.c +++ b/src/builtin/source.c @@ -3,8 +3,8 @@ #include #include "builtin.h" -#include "input.h" #include "context.h" +#include "input.h" #include "parse.h" #include "run.h" #include "utils.h" diff --git a/src/context.h b/src/context.h index 87e9d64..4fa355e 100644 --- a/src/context.h +++ b/src/context.h @@ -1,9 +1,11 @@ -#define MAXCHARS 500 -#define MAXCMDS (MAXCHARS + 1) / 2 -#define MAXRDS (MAXCHARS / 3) +#define MAXCHARS 1000 +#define MAXCOMMANDS (MAXCHARS + 1) / 2 +#define MAXREDIRECTS (MAXCHARS / 3) -enum accessmode { - END, +#define PIPELINE(name) struct context *name(struct context *context) + +enum access { + NONE, READ = '<', READWRITE, WRITE = '>', @@ -11,9 +13,10 @@ enum accessmode { }; struct redirect { - enum accessmode mode; + enum access mode; int oldfd, newfd; char *oldname; + struct redirect *next; }; enum terminator { @@ -24,20 +27,24 @@ enum terminator { OR, }; -struct cmd { +struct command { char **args; - struct redirect *r, rds[MAXRDS + 1]; + struct redirect *r; enum terminator term; int pipe[2]; - struct cmd *prev, *next; + struct command *prev, *next; }; struct context { - char buffer[MAXCHARS + 1 + 1], *tokens[MAXCMDS + 1], *script, *string; struct { - char *m; - size_t l; - } map; - struct cmd cmds[MAXCMDS + 1]; - Input input; + char *string, *script; + struct { + char *map; + size_t len; + }; + PIPELINE((*input)); + }; + char buffer[MAXCHARS + 1 + 1], *tokens[MAXCOMMANDS + 1]; + struct redirect redirects[MAXREDIRECTS + 1]; + struct command commands[1 + MAXCOMMANDS]; }; diff --git a/src/history.c b/src/history.c index 093c95c..945064d 100644 --- a/src/history.c +++ b/src/history.c @@ -4,11 +4,12 @@ #include #include -#include "input.h" #include "context.h" +#include "input.h" #include "utils.h" #define MAXHIST 100 + #define INC(v) (history.v = (history.v + 1) % (MAXHIST + 1)) #define DEC(v) (history.v = (history.v + MAXHIST) % (MAXHIST + 1)) @@ -17,9 +18,9 @@ static struct { size_t b, c, t; } history; -void readhistory(void) { +void inithistory(void) { FILE *file; - + if (!catpath(home, ".ashhistory", history.path)) exit(EXIT_FAILURE); if (!(file = fopen(history.path, "r"))) { if (errno == ENOENT) return; @@ -52,7 +53,7 @@ void sethistory(char *buffer) { *history.entries[history.t] = '\0'; } -void writehistory(void) { +void deinithistory(void) { FILE *file; if (!(file = fopen(history.path, "w"))) { diff --git a/src/history.h b/src/history.h index 60b4bac..4c2428d 100644 --- a/src/history.h +++ b/src/history.h @@ -1,4 +1,4 @@ -void readhistory(void); +void inithistory(void); int gethistory(char direction, char *buffer); void sethistory(char *buffer); -void writehistory(void); +void deinithistory(void); diff --git a/src/input.c b/src/input.c index 559053f..0e5dc41 100644 --- a/src/input.c +++ b/src/input.c @@ -7,22 +7,21 @@ #include #include +#include "context.h" #include "history.h" #include "input.h" -#include "context.h" #include "utils.h" -#define DEFAULTPROMPT ">" - -INPUT(stringinput) { +PIPELINE(stringinput) { char *start; size_t l; if (!*context->string) { - if (context->script && munmap(context->map.m, context->map.l) == -1) + if (context->script && munmap(context->map, context->len) == -1) note("Unable to unmap memory associated with `%s'", context->script); return NULL; } + start = context->string; while (*context->string && *context->string != '\n') ++context->string; l = context->string - start; @@ -31,6 +30,7 @@ INPUT(stringinput) { note("Line too long, exceeds %d character limit", MAXCHARS); return NULL; } + strncpy(context->buffer, start, l); context->buffer[l] = ';'; context->buffer[l + 1] = '\0'; @@ -38,7 +38,7 @@ INPUT(stringinput) { return context; } -INPUT(scriptinput) { +PIPELINE(scriptinput) { int fd; struct stat sstat; @@ -50,8 +50,9 @@ INPUT(scriptinput) { note("Unable to stat `%s'", context->script); return NULL; } - if ((context->map.l = sstat.st_size) == 0) return NULL; - if ((context->string = context->map.m = mmap(NULL, context->map.l, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { + if ((context->len = sstat.st_size) == 0) return NULL; + if ((context->map = mmap(NULL, context->len, PROT_READ, MAP_PRIVATE, fd, 0)) + == MAP_FAILED) { note("Unable to memory map `%s'", context->script); return NULL; } @@ -59,28 +60,29 @@ INPUT(scriptinput) { note("Unable to close `%s'", context->script); return NULL; } + + context->string = context->map; context->input = stringinput; return context->input(context); } -static size_t prompt(void) { +static void prompt(void) { char *p; - if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = DEFAULTPROMPT, 1) == -1) + if (!(p = getenv("PROMPT")) && setenv("PROMPT", p = ">", 1) == -1) note("Unable to update $PROMPT$ environment variable"); - printf("%s ", p); - return strlen(p) + 1; + printf("\r%s ", p); } -INPUT(userinput) { +PIPELINE(userinput) { char *start, *cursor, *end; unsigned int c; int i; size_t oldlen, newlen; end = cursor = start = context->buffer; - *start = '\0'; + *context->buffer = '\0'; while (start == end) { prompt(); while ((c = getchar()) != '\r') switch (c) { @@ -98,7 +100,7 @@ INPUT(userinput) { break; case CTRLC: puts("^C\r"); - *start = '\0'; + *context->buffer = '\0'; return context; case CTRLD: puts("^D\r"); @@ -106,7 +108,7 @@ INPUT(userinput) { case CLEAR: fputs("\033[H\033[J", stdout); prompt(); - fputs(start, stdout); + fputs(context->buffer, stdout); continue; case ESCAPE: switch ((c = getchar())) { @@ -122,16 +124,17 @@ INPUT(userinput) { switch ((c = getchar())) { case UP: case DOWN: - oldlen = strlen(start); - if (!gethistory(c, start)) continue; - newlen = strlen(start); + oldlen = strlen(context->buffer); + if (!gethistory(c, context->buffer)) continue; + newlen = strlen(context->buffer); end = cursor = start + newlen; putchar('\r'); prompt(); - fputs(start, stdout); + fputs(context->buffer, stdout); for (i = oldlen - newlen; i > 0; --i) putchar(' '); for (i = oldlen - newlen; i > 0; --i) putchar('\b'); + break; case LEFT: if (cursor > start) putchar((--cursor, '\b')); @@ -161,7 +164,14 @@ INPUT(userinput) { } puts("\r"); } - sethistory(start); + + while (*start == ' ') ++start; + if (start == end) { + *context->buffer = '\0'; + return context; + } + + sethistory(context->buffer); *end++ = ';'; *end = '\0'; diff --git a/src/input.h b/src/input.h index 0b6dc8e..7ba2dcf 100644 --- a/src/input.h +++ b/src/input.h @@ -1,7 +1,3 @@ -#define INPUT(name) struct context *name(struct context *context) - -typedef INPUT((*Input)); - enum { CTRLC = '\003', CTRLD, @@ -18,6 +14,6 @@ enum { DEL = '\177', }; -INPUT(stringinput); -INPUT(scriptinput); -INPUT(userinput); +PIPELINE(stringinput); +PIPELINE(scriptinput); +PIPELINE(userinput); diff --git a/src/job.c b/src/job.c index 3829255..9c02e8b 100644 --- a/src/job.c +++ b/src/job.c @@ -1,6 +1,5 @@ #include #include -// #include // XXX #include "job.h" #include "utils.h" @@ -16,6 +15,13 @@ 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; @@ -29,10 +35,6 @@ struct job *pushjob(struct job *job) { return &p->job; } -struct job *peekjob(void) { - return jobs.active ? &jobs.active->job : NULL; -} - struct job *pulljob(void) { struct joblink *p; @@ -46,6 +48,10 @@ struct job *pulljob(void) { return &p->job; } +struct job *peekjob(void) { + return jobs.active ? &jobs.active->job : NULL; +} + struct job *searchjobid(pid_t id) { struct joblink *p; @@ -74,10 +80,3 @@ struct job *deletejobid(pid_t id) { return &p->job; } - -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; -} diff --git a/src/job.h b/src/job.h index f043286..f477750 100644 --- a/src/job.h +++ b/src/job.h @@ -9,10 +9,10 @@ struct job { enum jobtype type; }; +void initjobs(void); struct job *pushjob(struct job *job); -struct job *peekjob(void); struct job *pulljob(void); +struct job *peekjob(void); struct job *searchjobid(pid_t id); struct job *searchjobtype(enum jobtype); struct job *deletejobid(pid_t id); -void initjobs(void); diff --git a/src/main.c b/src/main.c index 982704f..c6dc202 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ #include -#include "input.h" #include "context.h" +#include "input.h" #include "options.h" #include "parse.h" #include "run.h" @@ -14,14 +14,14 @@ int main(int c, char **v) { options(); - initialize(); + init(); if (login) config(".ashlogin"); - if (interactive) config(".ashint"); + if (interactive) config(".ashrc"); while (run(parse(context.input(&context)))); - deinitialize(); + deinit(); return EXIT_SUCCESS; } diff --git a/src/options.c b/src/options.c index eb0e6db..35f39a3 100644 --- a/src/options.c +++ b/src/options.c @@ -1,14 +1,13 @@ -#include #include #include #include -#include "input.h" #include "context.h" +#include "input.h" +#include "utils.h" int login, interactive, argc; char **argv; - struct context context; static void usage(char *program, int code) { @@ -40,11 +39,11 @@ void options(void) { login = 1; break; case ':': - warnx("Expected argument following `-%c'\n", optopt); + note("Expected argument following `-%c'\n", optopt); usage(*argv, EXIT_FAILURE); case '?': default: - warnx("Unknown command line option `-%c'\n", optopt); + note("Unknown command line option `-%c'\n", optopt); usage(*argv, EXIT_FAILURE); } if (opt == 'c') break; diff --git a/src/parse.c b/src/parse.c index 10ac748..e36637e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -3,34 +3,37 @@ #include #include -#include "input.h" #include "context.h" +#include "input.h" #include "options.h" #include "utils.h" -static void initcmd(struct cmd *cmd) { - cmd->args = NULL; - cmd->r = cmd->rds; - cmd->r->mode = END; - cmd->prev = cmd - 1; - cmd->next = NULL; +static void initcommand(struct command *c) { + c->args = NULL; + c->r = NULL; + c->prev = c - 1; + c->next = NULL; } -struct context *parse(struct context *context) { +PIPELINE(parse) { char *b, **t, *name, *value, *stlend, *p, *end, *env; - struct cmd *c; + struct redirect *r, *q; + struct command *c; long l; int e, offset; if (!context) return NULL; + b = context->buffer; t = context->tokens; - c = context->cmds + 1; - context->cmds->next = NULL; + r = context->redirects; + c = context->commands + 1; + context->commands->next = NULL; *t = value = name = NULL; - for (initcmd(c); *b; ++b) switch (*b) { + r->mode = NONE; + for (initcommand(c); *b; ++b) switch (*b) { default: - if (c->r->mode) break; + if (r->mode) break; if (!c->args) c->args = t; if (!*(b - 1)) { if (!name) *t++ = b; else if (!value) value = b; @@ -38,25 +41,29 @@ struct context *parse(struct context *context) { break; case '<': case '>': - if (c->r->mode) { + if (r->mode) { note("File redirections should be separated by spaces"); return context; } - c->r->newfd = *b == '>'; + if (r - context->redirects == MAXREDIRECTS) { + note("Too many file redirects, exceeds %d redirect limit", MAXREDIRECTS); + return context; + } + if (!c->r) c->r = r; if (*(b - 1)) { if (c->args == --t) c->args = NULL; if ((l = strtol(*t, &stlend, 10)) < 0 || l > INT_MAX || stlend != b) { note("Invalid value for a file redirection"); return context; } - c->r->newfd = l; - } - c->r->mode = *b; + r->newfd = l; + } else r->newfd = *b == '>'; + r->mode = *b; if (*(b + 1) == '>') { - ++c->r->mode; + ++r->mode; ++b; } - c->r->oldname = b + 1; + r->oldname = b + 1; if (*(b + 1) == '&') ++b; break; case '"': @@ -95,6 +102,7 @@ struct context *parse(struct context *context) { *end = '\0'; memmove(p, p + 1, end - p); --b; + break; case '=': name = *--t; @@ -130,6 +138,7 @@ struct context *parse(struct context *context) { memmove(b + offset, b, end - b + 1); strncpy(p, env, e); b += offset - 1; + break; case '~': if (!*(b - 1)) { @@ -147,26 +156,27 @@ struct context *parse(struct context *context) { case '|': case ';': if (name && *c->args == name) c->args = NULL; - if (c->args || c->rds->mode) { + if (c->args || c->r) { if ((c->term = *b) == *(b + 1) && (*b == '&' || *b == '|')) { ++c->term; *b++ = '\0'; } *b = '\0'; - if (c->r->mode) (++c->r)->mode = END; - for (c->r = c->rds; c->r->mode; ++c->r) if (*c->r->oldname == '&') { - if ((l = strtol(++c->r->oldname, &stlend, 10)) < 0 - || l > INT_MAX || *stlend) { + + if (r->mode) { + r++->next = NULL; + r->mode = NONE; + } else if (c->r) (r - 1)->next = NULL; + for (q = c->r; q; q = q->next) if (*q->oldname == '&') { + if ((l = strtol(++q->oldname, &stlend, 10)) < 0 || l > INT_MAX || *stlend) { note("Incorrect syntax for file redirection"); return context; } - c->r->oldfd = l; - c->r->oldname = NULL; + q->oldfd = l; + q->oldname = NULL; } - c->r = c->rds; - c->next = c + 1; - initcmd(++c); + initcommand(c = c->next = c + 1); *t++ = NULL; } case ' ': @@ -178,7 +188,10 @@ struct context *parse(struct context *context) { } value = name = NULL; } - if (c->r->mode) (++c->r)->mode = END; + if (r->mode) { + r = r->next = r + 1; + r->mode = NONE; + } } (--c)->next = NULL; @@ -192,6 +205,7 @@ struct context *parse(struct context *context) { break; } - context->cmds->next = context->cmds + 1; + context->commands->next = context->commands + 1; + return context; } diff --git a/src/parse.h b/src/parse.h index c76ce9f..377fc37 100644 --- a/src/parse.h +++ b/src/parse.h @@ -1 +1 @@ -struct context *parse(struct context *context); +PIPELINE(parse); diff --git a/src/run.c b/src/run.c index add19cc..69c8dba 100644 --- a/src/run.c +++ b/src/run.c @@ -3,31 +3,32 @@ #include #include #include +#include #include #include -// #include // XXX #include "builtin.h" -#include "input.h" #include "context.h" #include "alias.h" +#include "input.h" #include "job.h" #include "fg.h" #include "utils.h" -static int closepipe(struct cmd *cmd) { +static int closepipe(struct command *command) { int result; - result = close(cmd->pipe[0]) == 0; - result &= close(cmd->pipe[1]) == 0; - if (!result) note("Unable to close `%s' pipe", *cmd->args); + result = close(command->pipe[0]) == 0; + result &= close(command->pipe[1]) == 0; + if (!result) note("Unable to close `%s' pipe", *command->args); + return result; } static void redirectfiles(struct redirect *r) { int mode, fd; - for (; r->mode; ++r) { + for (; r; r = r->next) { if (r->oldname) { switch (r->mode) { case READ: @@ -55,105 +56,111 @@ static void redirectfiles(struct redirect *r) { } } -static void exec(struct cmd *cmd) { +static void exec(struct command *c) { char cwd[PATH_MAX]; - redirectfiles(cmd->rds); - if (isbuiltin(cmd->args)) exit(status); - execvp(*cmd->args, cmd->args); + redirectfiles(c->r); + + if (isbuiltin(c->args)) exit(status); + execvp(*c->args, c->args); if (!getcwd(cwd, PATH_MAX)) fatal("Unable to check current working directory"); - execvP(*cmd->args, cwd, cmd->args); - fatal("Couldn't find `%s' command", *cmd->args); + execvP(*c->args, cwd, c->args); + + fatal("Couldn't find `%s' command", *c->args); } -int run(struct context *context) { - struct cmd *cmd; +PIPELINE(run) { + struct command *c; int ispipe, ispipestart, ispipeend; pid_t cpid, jobid; struct job job; - if (!context) return 0; + if (!context) return NULL; - applyaliases(cmd = context->cmds); + applyaliases(c = context->commands); setsigchld(&sigdfl); - while ((cmd = cmd->next)) { - if (!cmd->args) { - if (!cmd->r->mode) break; - if ((cpid = fork()) == -1) { - note("Unable to create child process"); - break; - } else if (cpid == 0) { - redirectfiles(cmd->r); - exit(EXIT_SUCCESS); - } - continue; - } - - ispipe = cmd->term == PIPE || cmd->prev->term == PIPE; - ispipestart = ispipe && cmd->prev->term != PIPE; - ispipeend = ispipe && cmd->term != PIPE; + while ((c = c->next)) if (c->args) { + ispipe = c->term == PIPE || c->prev->term == PIPE; + ispipestart = ispipe && c->prev->term != PIPE; + ispipeend = ispipe && c->term != PIPE; if (ispipe) { - if (!ispipeend && pipe(cmd->pipe) == -1) { + if (!ispipeend && pipe(c->pipe) == -1) { note("Unable to create pipe"); - if (!ispipestart) closepipe(cmd->prev); + if (!ispipestart) closepipe(c->prev); break; } if ((jobid = cpid = fork()) == -1) { - note("Unable to create child process"); + note("Unable to fork child process"); break; } else if (cpid == 0) { if (!ispipestart) { - if (dup2(cmd->prev->pipe[0], 0) == -1) - fatal("Unable to duplicate read end of `%s' pipe", *cmd->prev->args); - if (!closepipe(cmd->prev)) exit(EXIT_FAILURE); + if (dup2(c->prev->pipe[0], 0) == -1) + fatal("Unable to duplicate read end of `%s' pipe", *c->prev->args); + if (!closepipe(c->prev)) exit(EXIT_FAILURE); } if (!ispipeend) { - if (dup2(cmd->pipe[1], 1) == -1) - fatal("Unable to duplicate write end of `%s' pipe", *cmd->args); - if (!closepipe(cmd)) exit(EXIT_FAILURE); + if (dup2(c->pipe[1], 1) == -1) + fatal("Unable to duplicate write end of `%s' pipe", *c->args); + if (!closepipe(c)) exit(EXIT_FAILURE); } - exec(cmd); + exec(c); } if (!ispipestart) { - closepipe(cmd->prev); + closepipe(c->prev); jobid = (ispipeend ? pulljob : peekjob)()->id; } - } else if (!cmd->rds->mode && isbuiltin(cmd->args)) cpid = 0; + } else if (!c->r && isbuiltin(c->args)) cpid = 0; else if ((jobid = cpid = fork()) == -1) { - note("Unable to create child process"); + note("Unable to fork child process"); break; - } else if (cpid == 0) exec(cmd); + } else if (cpid == 0) exec(c); if (cpid) { if (setpgid(cpid, jobid) == -1) { if (errno != ESRCH) { - note("Unable to set pgid of `%s' command to %d", *cmd->args, jobid); + note("Unable to set pgid of `%s' command to %d", *c->args, jobid); if (kill(cpid, SIGKILL) == -1) note("Unable to kill process %d; may need to manually terminate", cpid); } break; } job = (struct job){.id = jobid, .config = canonical, .type = BACKGROUND}; - if (ispipestart || cmd->term == BG) { + if (ispipestart || c->term == BG) { if (!pushjob(&job)) { note("Unable to add job to background; too many background jobs"); - if (ispipestart) closepipe(cmd); + if (ispipestart) closepipe(c); break; } - } else if (cmd->term != PIPE) { + } else if (c->term != PIPE) { if (!setfg(job)) break; waitfg(job); } } - if (cmd->term == AND && status != EXIT_SUCCESS) break; - if (cmd->term == OR && status == EXIT_SUCCESS) break; + if (c->term == AND && status != EXIT_SUCCESS) break; + if (c->term == OR && status == EXIT_SUCCESS) break; + } else { + if (c->term == AND || c->term == PIPE || c->term == OR) { + note("Expected command"); + break; + } + if (!c->r) break; + + if ((cpid = fork()) == -1) { + note("Unable to fork child process"); + break; + } else if (cpid == 0) { + redirectfiles(c->r); + exit(EXIT_SUCCESS); + } + waitpid(cpid, NULL, 0); + errno = 0; // waitpid() might set errno } setsigchld(&sigchld); - return 1; + return context; } diff --git a/src/run.h b/src/run.h index 4f79635..e7eaa08 100644 --- a/src/run.h +++ b/src/run.h @@ -1,3 +1,3 @@ extern int status; -int run(struct context *context); +PIPELINE(run); diff --git a/src/utils.c b/src/utils.c index dfcb36f..b95bcf9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -21,7 +21,7 @@ void note(char *fmt, ...) { va_start(args, fmt); (errno ? vwarn : vwarnx)(fmt, args); va_end(args); - putchar('\r'); + putc('\r', stderr); errno = 0; } @@ -30,27 +30,26 @@ void fatal(char *fmt, ...) { va_start(args, fmt); (errno ? vwarn : vwarnx)(fmt, args); va_end(args); - putchar('\r'); + putc('\r', stderr); exit(EXIT_FAILURE); } -void initialize(void) { +void init(void) { char *shlvlstr, buffer[19 + 1]; long shlvl; - initterm(); - if (!(home = getenv("HOME"))) fatal("Unable to locate user's home directory, $HOME$ not set"); if (!(shlvlstr = getenv("SHLVL"))) shlvlstr = "0"; if ((shlvl = strtol(shlvlstr, NULL, 10)) < 0) shlvl = 0; - sprintf(shlvlstr = buffer, "%ld", shlvl + 1); - if (setenv("SHLVL", shlvlstr, 1) == -1) + sprintf(buffer, "%ld", shlvl + 1); + if (setenv("SHLVL", buffer, 1) == -1) note("Unable to update $SHLVL$ environment variable"); - if (interactive) readhistory(); + initfg(); initjobs(); + if (interactive) inithistory(); } char *catpath(char *dir, char *filename, char *buffer) { @@ -69,8 +68,7 @@ char *catpath(char *dir, char *filename, char *buffer) { return buffer; } -void deinitialize(void) { - deinitterm(); - - if (interactive) writehistory(); +void deinit(void) { + if (interactive) deinithistory(); + deinitfg(); } diff --git a/src/utils.h b/src/utils.h index 3884832..c2884c0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,6 +3,6 @@ extern int status; void note(char *fmt, ...); void fatal(char *fmt, ...); -void initialize(void); +void init(void); char *catpath(char *dir, char *filename, char *buffer); -void deinitialize(void); +void deinit(void); -- 2.51.0