-Subproject commit 47569fbe806a5138763e7ef3447dca254357dff8
+Subproject commit 4711a83fafa0282fadeaba701a25539b3e73d073
if (sigaction(SIGCHLD, &sigdfl, NULL) == -1) {
note("Unable to acquire lock on the job stack");
- return 1;
+ return EXIT_FAILURE;
}
if (argv[1]) {
if ((jobid = strtol(argv[1], NULL, 10)) == LONG_MAX && errno
|| jobid <= 0) {
note("Invalid job id");
- return 1;
+ return EXIT_FAILURE;
}
if (!(job = findjob((pid_t)jobid))) {
note("Unable to find job %d", (pid_t)jobid);
- return 1;
+ return EXIT_FAILURE;
}
if (job->type == BACKGROUND) {
note("Job %d already in background", (pid_t)jobid);
- return 1;
+ return EXIT_FAILURE;
}
} else {
for (jobs.c = MINUSONE(jobs, t); jobs.c != MINUSONE(jobs, b); DEC(jobs, c))
if (CURRENT->type == SUSPENDED) break;
if (jobs.c == MINUSONE(jobs, b)) {
note("No suspended jobs to run in background");
- return 1;
+ return EXIT_FAILURE;
}
}
job = deletejob();
if (!(push(&jobs, job))) {
note("Unable to add job to background; too many jobs");
- return 1;
+ return EXIT_FAILURE;
}
if (killpg(job->id, SIGCONT) == -1) {
note("Unable to wake up suspended process group %d", job->id);
- return 1;
+ return EXIT_FAILURE;
}
job->type = BACKGROUND;
if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
note("Unable to install SIGCHLD handler");
- return 1;
+ return EXIT_FAILURE;
}
- return 0;
+ return EXIT_SUCCESS;
}
BUILTINSIG(cd) {
char *fullpath;
- if (argv[1]) {
- if (!(fullpath = realpath(argv[1], NULL))) {
- note("Could not resolve path name");
- return 1;
- }
- } else fullpath = home;
+ if (!argv[1]) fullpath = home;
+ else if (!(fullpath = realpath(argv[1], NULL))) {
+ note("Could not resolve path name");
+ return EXIT_FAILURE;
+ }
+
if (chdir(fullpath) == -1) {
note("Unable to change directory to `%s'", argv[1]);
- return 1;
+ return EXIT_FAILURE;
}
+
if (setenv("PWD", fullpath, 1) == -1)
note("Unable to change $PWD$ to `%s'", fullpath);
+
if (fullpath != home) free(fullpath);
- return 0;
+
+ return EXIT_SUCCESS;
}
if (sigaction(SIGCHLD, &sigdfl, NULL) == -1) {
note("Unable to acquire lock on the job stack");
- return 1;
+ return EXIT_FAILURE;
}
if (argv[1]) {
if ((jobid = strtol(argv[1], NULL, 10)) == LONG_MAX && errno
|| jobid <= 0) {
note("Invalid process group id");
- return 1;
+ return EXIT_FAILURE;
}
if (!(job = findjob((pid_t)jobid))) {
note("Unable to find process group %d", (pid_t)jobid);
- return 1;
+ return EXIT_FAILURE;
}
job = deletejob();
} else if (!(job = pull(&jobs))) {
note("No processes to bring into the foreground");
- return 1;
+ return EXIT_FAILURE;
}
if (sigaction(SIGCHLD, &sigchld, NULL) == -1) {
note("Unable to install SIGCHLD handler");
- return 1;
+ return EXIT_FAILURE;
}
- if (!setfg(*job)) return 1;
+ if (!setfg(*job)) return EXIT_FAILURE;
waitfg(*job);
- return 0;
+ return EXIT_SUCCESS;
}
return 1;
}
} else if (errno != ENOENT) note("Unable to check if `%s' exists", filepath);
+
return 0;
}
struct builtin *builtin;
char *path, *dir, *p;
- if (!argv[1]) return 1;
+ if (!argv[1]) return EXIT_FAILURE;
for (builtin = builtins; builtin->func; ++builtin)
if (strcmp(argv[1], builtin->name) == 0) {
- puts("Built-in command\r");
- return 0;
+ printf("%s is built-in\r\n", argv[1]);
+ return EXIT_SUCCESS;
}
if (!(path = getenv("PATH"))) {
note("Unable to examine $PATH$");
- return 1;
+ return EXIT_FAILURE;
}
if (!(path = p = strdup(path))) {
note("Unable to duplicate $PATH$");
- return 1;
+ return EXIT_FAILURE;
}
do {
if (!(dir = p)) break;
if ((p = strchr(dir, ':'))) *p++ = '\0';
} while (!inpath(dir, argv[1]));
free(path);
- if (dir) return 0;
+ if (dir) return EXIT_SUCCESS;
printf("%s not found\r\n", argv[1]);
- return 1;
+ return EXIT_FAILURE;
}
#define DEFAULTPROMPT ">"
#define HISTORYFILE ".ashhistory"
-#define INTERACTIVEFILE ".ashinteractive"
+#define INTFILE ".ashint"
#define LOGINFILE ".ashlogin"
#define MAXBUILTINS 100 // Maximum number of builtin commands
}
char *config(char *name) {
+ int fd;
char *result;
static char *origscript, *origstr;
script = catpath(home, name);
}
+ if ((fd = open(script, O_RDONLY | O_CREAT, 0644)) == -1)
+ fatal("Unable to open `%s'\n", script);
+ if (close(fd) == -1)
+ fatal("Unable to close `%s'", script);
+
if (!(result = scriptinput())) {
script = origscript;
string = origstr;
initialize();
if (login) while (run(parse(config(LOGINFILE))));
- if (interactive) while (run(parse(config(INTERACTIVEFILE))));
+ if (interactive) while (run(parse(config(INTFILE))));
while (run(parse(input())));
#include <limits.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "input.h"
#include "options.h"
#include "parse.h"
+#include "run.h"
#include "utils.h"
static char *tokens[MAXCHARS + 1];
static struct cmd cmds[MAXCMDS + 1];
-struct cmd empty = {0};
+
+static void initcmd(struct cmd *cmd) {
+ cmd->args = NULL;
+ cmd->r = cmd->rds;
+ cmd->r->mode = END;
+ cmd->prev = cmd - 1;
+ cmd->next = NULL;
+}
struct cmd *parse(char *b) {
char **t, *name, *value, *stlend, *p, *end, *env;
if (!b) return NULL;
t = tokens;
c = cmds;
+ c->next = c + 1;
value = name = NULL;
- for (c->args = NULL, c->r = c->rds; *b; ++b) switch (*b) {
+ for (initcmd(++c); *b; ++b) switch (*b) {
default:
+ if (c->r->mode) break;
if (!c->args) c->args = t;
if (!*(b - 1)) {
if (!name) *t++ = b; else if (!value) value = b;
break;
case '<':
case '>':
+ if (c->r->mode) {
+ note("File redirections should be separated by spaces");
+ return c;
+ }
c->r->newfd = *b == '>';
if (*(b - 1)) {
if (c->args == --t) c->args = NULL;
if ((l = strtol(*t, &stlend, 10)) < 0 || l > INT_MAX || stlend != b) {
- note("Incorrect syntax for file redirection");
- return ∅
+ note("Invalid value for a file redirection");
+ return c;
}
c->r->newfd = l;
}
++c->r->mode;
++b;
}
- c->r++->oldname = b + 1;
+ c->r->oldname = b + 1;
if (*(b + 1) == '&') ++b;
break;
case '"':
}
if (!b) {
note("Quote left open-ended");
- return ∅
+ return c;
}
memmove(p, p + 1, end-- - p);
--b;
while (*b && *b != '$') ++b;
if (!*b) {
note("Environment variable lacks a terminating `$'");
- return ∅
+ return c;
}
*b++ = '\0';
for (end = b; *end; ++end);
l = strtol(p + 1, &stlend, 10);
if (stlend == b - 1) env = l >= 0 && l < argc ? argv[l] : b - 1;
- else if ((env = getenv(p + 1)) == NULL) {
+ else if (strcmp(p + 1, "?") == 0) {
+ if (!sprintf(env = (char [12]){0}, "%d", status)) {
+ note("Unable to get previous command status");
+ return c;
+ }
+ } else if ((env = getenv(p + 1)) == NULL) {
note("Environment variable does not exist");
- return ∅
+ return c;
}
+
e = strlen(env);
offset = e - (b - p);
- memmove(b + offset, b, end - b);
+ memmove(b + offset, b, end - b + 1);
strncpy(p, env, e);
b += offset - 1;
- *(end + offset) = '\0';
+ break;
+ case '~':
+ if (!*(b - 1)) {
+ if (!name) *t++ = b; else if (!value) value = b;
+ }
+ for (end = b; *end; ++end);
+ offset = strlen(home);
+ memmove(b + offset, b + 1, end - b);
+ strncpy(b, home, offset);
+ b += offset - 1;
break;
case '#':
*(b + 1) = '\0';
case '|':
case ';':
if (name && *c->args == name) c->args = NULL;
- if (c->args) {
+ if (c->args || c->rds->mode) {
if ((c->term = *b) == *(b + 1) && (*b == '&' || *b == '|')) {
++c->term;
*b++ = '\0';
}
*b = '\0';
- c->r->mode = END;
+ 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) {
note("Incorrect syntax for file redirection");
- return ∅
+ return c;
}
c->r->oldfd = l;
c->r->oldname = NULL;
}
+ c->r = c->rds;
+ c->next = c + 1;
- (++c)->args = NULL;
+ initcmd(++c);
*t++ = NULL;
}
- c->r = c->rds;
case ' ':
*b = '\0';
if (value) {
if (setenv(name, value, 1) == -1) {
note("Unable to set environment variable");
- return ∅
+ return c;
}
value = name = NULL;
}
+ if (c->r->mode) (++c->r)->mode = END;
}
- if (c-- != cmds) switch (c->term) {
+ (--c)->next = NULL;
+ switch (c->term) {
case AND:
case PIPE:
case OR:
note("Expected another command");
- return ∅
+ return c;
default:
break;
}
struct redirect *r, rds[MAXRDS + 1];
enum terminator term;
int pipe[2];
+ struct cmd *prev, *next;
};
-extern struct cmd empty;
-
struct cmd *parse(char *b);
#include "stack.h"
#include "utils.h"
+int status;
+
static int closepipe(struct cmd *cmd) {
int result;
}
}
+static void exec(struct cmd *cmd) {
+ char *cwd;
+
+ execvp(*cmd->args, cmd->args);
+ if (!(cwd = getcwd(NULL, 0)))
+ fatal("Unable to check current working directory");
+ execvP(*cmd->args, cwd, cmd->args);
+ free(cwd);
+ fatal("Couldn't find `%s' command", *cmd->args);
+}
+
int run(struct cmd *cmd) {
- struct cmd *prev;
int ispipe, ispipestart, ispipeend;
- static int status;
pid_t cpid, jobid;
struct job job;
if (!cmd) return 0;
- for (prev = ∅ cmd->args; prev = cmd++) {
- ispipe = cmd->term == PIPE || prev->term == PIPE;
- ispipestart = ispipe && prev->term != PIPE;
+ 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;
if (ispipe) {
if (!ispipeend && pipe(cmd->pipe) == -1) {
note("Unable to create pipe");
- if (!ispipestart) closepipe(prev);
+ if (!ispipestart) closepipe(cmd->prev);
break;
}
if ((jobid = cpid = fork()) == -1) {
break;
} else if (cpid == 0) {
if (!ispipestart) {
- if (dup2(prev->pipe[0], 0) == -1)
- fatal("Unable to duplicate read end of `%s' pipe", *prev->args);
- if (!closepipe(prev)) exit(EXIT_FAILURE);
+ 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 (!ispipeend) {
if (dup2(cmd->pipe[1], 1) == -1)
}
redirectfiles(cmd->rds);
- if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS);
- if (execvp(*cmd->args, cmd->args) == -1)
- fatal("Couldn't find `%s' command", *cmd->args);
+ if (isbuiltin(cmd->args, &status)) exit(status);
+ exec(cmd);
}
if (!ispipestart) {
- closepipe(prev);
+ closepipe(cmd->prev);
jobid = ((struct job *)(ispipeend ? pull : peek)(&jobs))->id;
}
- } else {
- if (cmd->rds->mode == END && isbuiltin(cmd->args, &status)) break;
- if ((jobid = cpid = fork()) == -1) {
- note("Unable to create child process");
- break;
- } else if (cpid == 0) {
- redirectfiles(cmd->rds);
- if (isbuiltin(cmd->args, &status)) exit(EXIT_SUCCESS);
- if (execvp(*cmd->args, cmd->args) == -1)
- fatal("Couldn't find `%s' command", *cmd->args);
- }
- }
-
- if (setpgid(cpid, jobid) == -1) {
- if (errno != ESRCH) {
- note("Unable to set pgid of `%s' command to %d", *cmd->args, jobid);
- if (kill(cpid, SIGKILL) == -1)
- note("Unable to kill process %d; may need to manually terminate", cpid);
- }
+ } else if (!cmd->rds->mode && isbuiltin(cmd->args, &status)) cpid = 0;
+ else if ((jobid = cpid = fork()) == -1) {
+ note("Unable to create child process");
break;
+ } else if (cpid == 0) {
+ redirectfiles(cmd->rds);
+ if (isbuiltin(cmd->args, &status)) exit(status);
+ exec(cmd);
}
- job = (struct job){.id = jobid, .config = canonical, .type = BACKGROUND};
- if (ispipestart || cmd->term == BG) {
- if (!push(&jobs, &job)) {
- note("Unable to add job to background; too many background jobs");
- if (ispipestart) closepipe(cmd);
+
+ if (cpid) {
+ if (setpgid(cpid, jobid) == -1) {
+ if (errno != ESRCH) {
+ note("Unable to set pgid of `%s' command to %d", *cmd->args, jobid);
+ if (kill(cpid, SIGKILL) == -1)
+ note("Unable to kill process %d; may need to manually terminate", cpid);
+ }
break;
}
- } else if (cmd->term != PIPE) {
- if (!setfg(job)) break;
- status = waitfg(job);
-
- if (cmd->term == AND && status != 0) break;
- if (cmd->term == OR && status == 0) break;
+ job = (struct job){.id = jobid, .config = canonical, .type = BACKGROUND};
+ if (ispipestart || cmd->term == BG) {
+ if (!push(&jobs, &job)) {
+ note("Unable to add job to background; too many background jobs");
+ if (ispipestart) closepipe(cmd);
+ break;
+ }
+ } else if (cmd->term != PIPE) {
+ if (!setfg(job)) break;
+ status = waitfg(job);
+ }
}
+
+ if (cmd->term == AND && status != EXIT_SUCCESS) break;
+ if (cmd->term == OR && status == EXIT_SUCCESS) break;
}
return 1;
+extern int status;
+
int run(struct cmd *cmd);