summaryrefslogtreecommitdiff
path: root/usr.bin/osh
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/osh')
-rw-r--r--usr.bin/osh/osh.c135
1 files changed, 92 insertions, 43 deletions
diff --git a/usr.bin/osh/osh.c b/usr.bin/osh/osh.c
index 5bcd2e2..af7f4ab 100644
--- a/usr.bin/osh/osh.c
+++ b/usr.bin/osh/osh.c
@@ -30,7 +30,9 @@
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/reboot.h>
+#include <sys/errno.h>
#include <sys/spawn.h>
+#include <sys/wait.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdbool.h>
@@ -38,7 +40,9 @@
#include <string.h>
#include <stdio.h>
+#define is_printable(C) ((C) >= 32 && (C) <= 126)
#define is_ascii(C) ((C) >= 0 && (C) <= 128)
+
#define COMMENT '@'
#define WELCOME \
":::::::::::::::::::::::::::::::::::::::\n" \
@@ -63,7 +67,6 @@
#define PROMPT "[%s::osmora]~ "
static char buf[64];
-static uint8_t buf_i;
static int running;
static int bell_fd;
static bool bs_bell = true; /* Beep on backspace */
@@ -81,6 +84,15 @@ struct builtin_cmd {
void (*func)(int argc, char *argv[]);
};
+/*
+ * Results after parsing a command
+ *
+ * @bg: Run command in background
+ */
+struct parse_state {
+ uint8_t bg : 1;
+};
+
static struct builtin_cmd cmds[] = {
{"help",cmd_help},
{"exit",cmd_exit},
@@ -143,7 +155,7 @@ cmd_bell(int argc, char *argv[])
}
static int
-parse_args(char *input, char *argv[], int max_args)
+parse_args(char *input, char *argv[], int max_args, struct parse_state *p)
{
int argc = 0;
@@ -152,6 +164,10 @@ parse_args(char *input, char *argv[], int max_args)
return 0;
}
+ /* setup default state */
+ p->bg = 0;
+
+ /* parse loop */
while (*input != '\0') {
/* skip leading spaces */
while (*input == ' ') {
@@ -168,6 +184,11 @@ parse_args(char *input, char *argv[], int max_args)
break;
}
+ /* run in background? */
+ if (*input == '&') {
+ p->bg = 1;
+ }
+
if (argc < max_args) {
argv[argc++] = input; /* mark start of the argument */
}
@@ -191,14 +212,18 @@ parse_args(char *input, char *argv[], int max_args)
return argc;
}
-static char *
+/*
+ * Grab a string from stdin and return
+ * the resulting offset within the input
+ * buffer we are at.
+ */
+static uint8_t
getstr(void)
{
char c;
int input;
uint32_t beep_payload;
-
- buf_i = 0;
+ uint8_t buf_i = 0;
/*
* Prepare the beep payload @ 500 Hz
@@ -221,7 +246,7 @@ getstr(void)
if (c == '\n') {
buf[buf_i] = '\0';
putchar('\n');
- return buf;
+ return buf_i;
}
/* handle backspaces and DEL */
@@ -232,7 +257,7 @@ getstr(void)
} else if (bell_fd > 0 && bs_bell) {
write(bell_fd, &beep_payload, sizeof(beep_payload));
}
- } else if (is_ascii(c) && buf_i < sizeof(buf) - 1) {
+ } else if (is_printable(c) && buf_i < sizeof(buf) - 1) {
/* write to fd and add to buffer */
buf[buf_i++] = c;
putchar(c);
@@ -250,16 +275,11 @@ builtin_run(struct builtin_cmd *cmd, int argc, char *argv[])
}
static int
-cmd_run(const char *input, int argc, char *argv[], bool wait)
+cmd_run(const char *input, int argc, char *argv[])
{
char bin_path[512];
char *envp[1] = { NULL };
- int error, spawn_flags = 0;
-
- /* Should we wait or daemonize? */
- if (wait) {
- spawn_flags |= SPAWN_WAIT;
- }
+ pid_t child;
/*
* If we can access the raw input as a file, try to
@@ -268,11 +288,11 @@ cmd_run(const char *input, int argc, char *argv[], bool wait)
* path directly into the console.
*/
if (access(input, F_OK) == 0) {
- error = spawn(input, argv, envp, spawn_flags);
- if (error < 0) {
- return error;
+ child = spawn(input, argv, envp, 0);
+ if (child < 0) {
+ return child;
}
- return 0;
+ return child;
}
snprintf(bin_path, sizeof(bin_path), "/usr/bin/%s", input);
@@ -282,11 +302,11 @@ cmd_run(const char *input, int argc, char *argv[], bool wait)
return -1;
}
- if ((error = spawn(bin_path, argv, envp, spawn_flags)) < 0) {
- return error;
+ if ((child = spawn(bin_path, argv, envp, 0)) < 0) {
+ return child;
}
- return 0;
+ return child;
}
/*
@@ -295,27 +315,29 @@ cmd_run(const char *input, int argc, char *argv[], bool wait)
* @input: Command input
* @argc: Argument count
* @argv: Argument vector
- * @wait: If false, program will be daemonized
*/
-static void
-command_match(const char *input, int argc, char *argv[], bool wait)
+static int
+command_match(const char *input, int argc, char *argv[])
{
int found = 0;
int i;
+ pid_t child = -1;
for (i = 0; cmds[i].name != NULL; i++) {
if (strcmp(input, cmds[i].name) == 0) {
builtin_run(&cmds[i], argc, argv);
found = 1;
- break;
}
}
if (found == 0) {
- if (cmd_run(input, argc, argv, wait) < 0) {
+ if ((child = cmd_run(input, argc, argv)) < 0) {
puts("Unrecognized command");
+ return -1;
}
}
+
+ return child;
}
static void
@@ -329,11 +351,45 @@ script_skip_comment(int fd)
}
}
+/*
+ * Parse a single line typed in from the
+ * user.
+ *
+ * @input: Input line
+ */
+static int
+parse_line(char *input)
+{
+ int argc;
+ char *argv[16];
+ struct parse_state state = {0};
+ pid_t child;
+
+ /* Ensure the aux vector is zeored */
+ memset(argv, 0, sizeof(argv));
+
+ /*
+ * Grab args from the user, there should be
+ * at least one.
+ */
+ argc = parse_args(input, argv, sizeof(argv), &state);
+ if (argc == 0) {
+ return -EAGAIN;
+ }
+
+ child = command_match(input, argc, argv);
+ if (child > 0 && !state.bg) {
+ waitpid(child, NULL, 0);
+ }
+
+ return 0;
+}
+
static int
open_script(const char *pathname)
{
int fd, argc, buf_i = 0;
- char c, *input, *argv[16];
+ char c, *input;
char buf[256];
fd = open(pathname, O_RDONLY);
@@ -360,11 +416,7 @@ open_script(const char *pathname)
if (c == '\n') {
buf[buf_i] = '\0';
- argc = parse_args(buf, argv, sizeof(argv));
- command_match(buf, argc, argv, true);
-
- argv[0] = NULL;
- argv[1] = NULL;
+ parse_line(buf);
buf_i = 0;
continue;
}
@@ -379,35 +431,32 @@ main(int argc, char **argv)
{
int found, prog_argc;
int stdout_fd;
- char *input, *prog_argv[16], *p;
+ uint8_t buf_i;
+ char *p;
char c;
+ pid_t child;
if (argc > 1) {
return open_script(argv[1]);
}
- buf_i = 0;
running = 1;
- found = 0;
bell_fd = open("/dev/beep", O_WRONLY);
-
puts(WELCOME);
+
while (running) {
- memset(prog_argv, 0, sizeof(prog_argv));
printf(PROMPT, getlogin());
- input = getstr();
- if (input[0] == '\0') {
+ buf_i = getstr();
+ if (buf[0] == '\0') {
continue;
}
- prog_argc = parse_args(input, prog_argv, sizeof(prog_argv));
- if (prog_argc == 0) {
+ buf[buf_i] = '\0';
+ if (parse_line(buf) < 0) {
continue;
}
- command_match(input, prog_argc, prog_argv, true);
- found = 0;
buf[0] = '\0';
}
return 0;