diff options
Diffstat (limited to 'usr.bin/osh')
-rw-r--r-- | usr.bin/osh/osh.c | 135 |
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; |