#include <stddef.h>
#include <stdlib.h>
#include <err.h>
+#include <limits.h>
#include <stdio.h> // 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;
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;
}
++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 '&':
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;
#include <err.h>
+#include <fcntl.h>
#include <signal.h>
+#include <stdio.h> // DEBUG
#include <stdlib.h>
#include <string.h>
#include <sys/errno.h>
#include <termios.h>
#include <unistd.h>
-#include <stdio.h> // DEBUG
#include "builtins.h"
#include "stack.h"
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;
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;
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);
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) {