From 9a15929320bce68676de7110b50257ebe50ba1e6 Mon Sep 17 00:00:00 2001 From: Trent Huber Date: Thu, 3 Jul 2025 02:32:22 -0400 Subject: [PATCH] File redirection implementation complete --- src/lex.c | 73 ++++++++++++++++++++++++++++++++++++++---------------- src/lex.h | 2 +- src/main.c | 55 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 102 insertions(+), 28 deletions(-) diff --git a/src/lex.c b/src/lex.c index 642e2c8..0def809 100644 --- a/src/lex.c +++ b/src/lex.c @@ -2,18 +2,21 @@ #include #include #include +#include #include // DEBUG #include "history.h" #include "lex.h" static char *tokens[1 + BUFLEN + 1]; -static struct cmd cmds[1 + (BUFLEN + 1) / 2 + 1] = {{.args = tokens, .f = cmds->freds}}; +static struct cmd cmds[1 + (BUFLEN + 1) / 2 + 1] = {{.args = tokens}}; void printfreds(struct cmd *c) { - for (; c->f->mode != END; ++c->f) { - printf("%d", c->f->newfd); - switch (c->f->mode) { + struct fred *f; + + for (f = c->freds; f->mode != END; ++f) { + printf("%d ", f->newfd); + switch (f->mode) { case READ: fputs("<", stdout); break; @@ -28,13 +31,23 @@ void printfreds(struct cmd *c) { break; default:; } - puts(c->f->old.name); + switch (f->type) { + case FD: + printf(" #%d\n", f->old.fd); + break; + case NAME: + printf(" %s\n", f->old.name); + break; + default:; + } } } struct cmd *lex(char *b) { char **t, *end; struct cmd *c; + struct fred *f; + long test; if (!b) return NULL; t = tokens; @@ -47,22 +60,29 @@ struct cmd *lex(char *b) { } ++b; break; + case ' ': + *b++ = '\0'; + break; case '<': case '>': if (*(b - 1)) { - if ((c->f->newfd = strtol(*--t, &end, 10)) < 0 || end != b) { + if ((test = strtol(*--t, &end, 10)) < 0 || test > INT_MAX || end != b) { warnx("Invalid file redirection operator"); c->args = NULL; return c - 1; } + f->newfd = (int)test; if (c->args == t) c->args = NULL; - } else c->f->newfd = *b == '>'; - c->f->mode = *b++; + } else f->newfd = *b == '>'; + f->mode = *b++; if (*b == '>') { ++b; - ++c->f->mode; + ++f->mode; } - c->f++->old.name = b; + f->old.name = b; + + (++f)->mode = END; + if (*b == '&') ++b; break; case '&': @@ -71,29 +91,38 @@ struct cmd *lex(char *b) { case ';': if (c->args) { *t++ = NULL; - if (!*b) { - ++b; - ++c->type; + c->type = !*b ? *b++ + 1 : *b; + *b++ = '\0'; + for (f = c->freds; f->mode; ++f) { + if (*f->old.name == '&') { + if ((test = strtol(++f->old.name, &end, 10)) < 0 + || test > INT_MAX || (*end && !*f->old.name)) { + warnx("Invalid file redirection operator"); + c->args = NULL; + return c - 1; + } + f->type = FD; + f->old.fd = (int)test; + } else f->type = NAME; } - c->type += *b; - *(c->f) = (struct fred){0}; - c->f = c->freds; (++c)->args = NULL; + } else { + if (!*b) ++b; + *b++ = '\0'; } - c->f = c->freds; - case ' ': - *b++ = '\0'; + f = c->freds; + f->mode = END; } - switch (c->type) { + + switch ((c - 1)->type) { case AND: case PIPE: case OR: warnx("Command left open-ended"); - c->args = NULL; return c - 1; default: - *++c = (struct cmd){0}; + *c = (struct cmd){0}; } return cmds; diff --git a/src/lex.h b/src/lex.h index f3b26fb..e80a1d4 100644 --- a/src/lex.h +++ b/src/lex.h @@ -46,7 +46,7 @@ struct fred { struct cmd { char **args; enum terminator type; - struct fred *f, freds[(BUFLEN - 1) / 3 + 1]; + struct fred freds[(BUFLEN - 1) / 3 + 1]; int pipe[2]; }; diff --git a/src/main.c b/src/main.c index d090458..7080219 100644 --- a/src/main.c +++ b/src/main.c @@ -1,11 +1,12 @@ #include +#include #include +#include // DEBUG #include #include #include #include #include -#include // DEBUG #include "builtins.h" #include "stack.h" @@ -33,6 +34,46 @@ static int closepipe(struct cmd *cmd) { return result; } +static int redirectfiles(struct fred *f) { + int oflag, fd; + + for (; f->mode; ++f) { + if (f->type == NAME) { + switch (f->mode) { + case READ: + oflag = O_RDONLY; + break; + case WRITE: + oflag = O_WRONLY | O_CREAT | O_TRUNC; + break; + case READWRITE: + oflag = O_RDWR | O_CREAT | O_APPEND; + break; + case APPEND: + oflag = O_WRONLY | O_CREAT | O_APPEND; + break; + default:; + } + if ((fd = open(f->old.name, oflag, 0644)) == -1) { + warn("Unable to open `%s'", f->old.name); + return 0; + } + f->old.fd = fd; + } + if (dup2(f->old.fd, f->newfd) == -1) { + warn("Unable to redirect %d to %d", f->newfd, f->old.fd); + return 0; + } + if (f->type == NAME) { + if (close(f->old.fd) == -1) { + warn("Unable to close file descriptor %d", f->old.fd); + return 0; + } + } + } + return 1; +} + int main(void) { struct cmd *cmd, *prev; int ispipe, ispipestart, ispipeend, status; @@ -44,7 +85,6 @@ int main(void) { while ((cmd = lex(input()))) { while (prev = cmd++, cmd->args) { - printfreds(cmd); ispipe = cmd->type == PIPE || prev->type == PIPE; ispipestart = ispipe && prev->type != PIPE; ispipeend = ispipe && cmd->type != PIPE; @@ -72,6 +112,7 @@ int main(void) { if (!closepipe(cmd)) exit(EXIT_FAILURE); } + if (!redirectfiles(cmd->freds)) exit(EXIT_FAILURE); if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS); if (execvp(*cmd->args, cmd->args) == -1) err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args); @@ -81,12 +122,16 @@ int main(void) { jobid = ((struct job *)(ispipeend ? pull : peek)(&jobs))->id; } } else { - if (isbuiltin(cmd->args, &status)) break; + if (cmd->freds->mode == END && isbuiltin(cmd->args, &status)) break; if ((jobid = cpid = fork()) == -1) { warn("Unable to create child process"); break; - } else if (cpid == 0 && execvp(*cmd->args, cmd->args) == -1) - err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args); + } else if (cpid == 0) { + if (!redirectfiles(cmd->freds)) exit(EXIT_FAILURE); + if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS); + if (execvp(*cmd->args, cmd->args) == -1) + err(EXIT_FAILURE, "Couldn't find `%s' command", *cmd->args); + } } if (setpgid(cpid, jobid) == -1) { if (errno != ESRCH) { -- 2.51.0