diff options
Diffstat (limited to 'usr.bin/osh/osh.c')
-rw-r--r-- | usr.bin/osh/osh.c | 333 |
1 files changed, 271 insertions, 62 deletions
diff --git a/usr.bin/osh/osh.c b/usr.bin/osh/osh.c index 2f592ad..dd92378 100644 --- a/usr.bin/osh/osh.c +++ b/usr.bin/osh/osh.c @@ -29,63 +29,129 @@ #include <sys/types.h> #include <sys/cdefs.h> +#include <sys/reboot.h> +#include <sys/spawn.h> #include <fcntl.h> #include <stddef.h> +#include <stdbool.h> #include <unistd.h> #include <string.h> +#include <stdio.h> -#define prcons(FD, STR) write((FD), (STR), strlen((STR))) #define is_ascii(C) ((C) >= 0 && (C) <= 128) +#define COMMENT '@' #define WELCOME \ ":::::::::::::::::::::::::::::::::::::::\n" \ ":: OSMORA GATEWAY ~ Every key echos ::\n" \ ":: ..... Proceed with purpose ..... ::\n" \ - ":::::::::::::::::::::::::::::::::::::::\n" + ":::::::::::::::::::::::::::::::::::::::" #define HELP \ "Default commands:\n" \ - "help - Display this help message\n" \ - "echo - Print the arguments to the console\n" \ - "exit - Exit the shell\n" + "help - Display this help message\n" \ + "echo - Print the arguments to the console\n" \ + "reboot - Reboot the machine\n" \ + "shutdown - Power off the machine\n" \ + "kmsg - Print kernel message buffer\n" \ + "fetch - System information\n" \ + "kfg - Start up kfgwm\n" \ + "bell - Toggle backspace bell\n" \ + "date - Get the current date\n" \ + "clear - Clear the screen\n" \ + "exit - Exit the shell" #define PROMPT "[root::osmora]~ " static char buf[64]; -static uint8_t i; +static uint8_t buf_i; static int running; +static int bell_fd; +static bool bs_bell = true; /* Beep on backspace */ -struct command { +static void cmd_help(int argc, char *argv[]); +static void cmd_echo(int argc, char *argv[]); +static void cmd_exit(int argc, char *argv[]); +static void cmd_reboot(int argc, char *argv[]); +static void cmd_shutdown(int argc, char *argv[]); +static void cmd_bell(int argc, char *argv[]); +static void cmd_clear(int argc, char *argv[]); + +struct builtin_cmd { const char *name; - void (*func)(int fd, int argc, char *argv[]); + void (*func)(int argc, char *argv[]); +}; + +static struct builtin_cmd cmds[] = { + {"help",cmd_help}, + {"exit",cmd_exit}, + {"reboot",cmd_reboot}, + {"shutdown", cmd_shutdown}, + {"bell", cmd_bell}, + {"clear", cmd_clear}, + {NULL, NULL} }; -void -cmd_help(int fd, int argc, char *argv[]) +static void +cmd_help(int argc, char *argv[]) { - prcons(fd, HELP); + puts(HELP); } -void -cmd_exit(int fd, int argc, char *argv[]) +static void +cmd_exit(int argc, char *argv[]) { running = 0; } -void -cmd_echo(int fd, int argc, char *argv[]) +static void +cmd_reboot(int argc, char *argv[]) +{ + cpu_reboot(REBOOT_RESET); +} + +static void +cmd_shutdown(int argc, char *argv[]) +{ + cpu_reboot(REBOOT_POWEROFF | REBOOT_HALT); +} + +static void +cmd_clear(int argc, char *argv[]) +{ + fputs("\033[H", stdout); +} + +static void +cmd_bell(int argc, char *argv[]) { - for (i = 1; i < argc; i++) { - prcons(fd, argv[i]); - prcons(fd, " "); + const char *usage_str = "usage: bell [on/off]"; + const char *arg; + + if (argc < 2) { + puts(usage_str); + return; + } + + arg = argv[1]; + if (strcmp(arg, "on") == 0) { + bs_bell = true; + } else if (strcmp(arg, "off") == 0) { + bs_bell = false; + } else { + puts(usage_str); } - prcons(fd, "\n"); } -int +static int parse_args(char *input, char *argv[], int max_args) { int argc = 0; + /* ignore comments */ + if (*input == '@') { + return 0; + } + while (*input != '\0') { /* skip leading spaces */ while (*input == ' ') { @@ -97,11 +163,21 @@ parse_args(char *input, char *argv[], int max_args) break; } + /* comment? */ + if (*input == COMMENT) { + break; + } + if (argc < max_args) { argv[argc++] = input; /* mark start of the argument */ } /* move forward until next space or end */ while (*input != '\0' && *input != ' ') { + /* ignore comments */ + if (*input == COMMENT) { + return 0; + } + input++; } @@ -116,88 +192,221 @@ parse_args(char *input, char *argv[], int max_args) } static char * -getstr(int fd) +getstr(void) { char c; - uint8_t input; - i = 0; + int input; + uint32_t beep_payload; + + buf_i = 0; + + /* + * Prepare the beep payload @ 500 Hz + * for 20ms + */ + beep_payload = 500; + beep_payload |= (30 << 16); for (;;) { - if (read(fd, &input, 2) <= 0) { + if ((input = getchar()) < 0) { continue; } - c = input & 0xFF; + c = (char)input; + if (c == '\t') { + continue; + } /* return on newline */ if (c == '\n') { - buf[i] = '\0'; - write(fd, "\n", 1); + buf[buf_i] = '\0'; + putchar('\n'); return buf; } /* handle backspaces and DEL */ if (c == '\b' || c == 127) { - if (i > 0) { - i--; - write(fd, "\b \b", 3); + if (buf_i > 0) { + buf_i--; + fputs("\b \b", stdout); + } else if (bell_fd > 0 && bs_bell) { + write(bell_fd, &beep_payload, sizeof(beep_payload)); } - } else if (is_ascii(c) && i < sizeof(buf) - 1) { + } else if (is_ascii(c) && buf_i < sizeof(buf) - 1) { /* write to fd and add to buffer */ - buf[i++] = c; - write(fd, &c, 1); + buf[buf_i++] = c; + putchar(c); } } } -struct command cmds[] = { - {"help", cmd_help}, - {"echo", cmd_echo}, - {"exit", cmd_exit}, - {NULL, NULL} -}; +static void +builtin_run(struct builtin_cmd *cmd, int argc, char *argv[]) +{ + if (cmd->func != NULL) { + cmd->func(argc, argv); + return; + } +} -int -main(void) +static int +cmd_run(const char *input, int argc, char *argv[], bool wait) +{ + char bin_path[512]; + char *envp[1] = { NULL }; + int error, spawn_flags = 0; + + /* Should we wait or daemonize? */ + if (wait) { + spawn_flags |= SPAWN_WAIT; + } + + /* + * If we can access the raw input as a file, try to + * spawn it as a program. This case would run if for + * example, the user entered /usr/sbin/foo, or some + * path directly into the console. + */ + if (access(input, F_OK) == 0) { + error = spawn(input, argv, envp, spawn_flags); + if (error < 0) { + return error; + } + return 0; + } + + snprintf(bin_path, sizeof(bin_path), "/usr/bin/%s", input); + + /* See if we can access it */ + if (access(bin_path, F_OK) != 0) { + return -1; + } + + if ((error = spawn(bin_path, argv, envp, spawn_flags)) < 0) { + return error; + } + + return 0; +} + +/* + * Match a command with a builtin or binary + * + * @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) +{ + int found = 0; + int i; + + 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) { + puts("Unrecognized command"); + } + } +} + +static void +script_skip_comment(int fd) { - int fd, found, argc; - char *input, *argv[16]; char c; - if ((fd = open("/dev/console", O_RDWR)) < 0) { + while (c != '\n') { + if (read(fd, &c, 1) <= 0) + break; + } +} + +static int +open_script(const char *pathname) +{ + int fd, argc, buf_i = 0; + char c, *input, *argv[16]; + char buf[256]; + + fd = open(pathname, O_RDONLY); + if (fd < 0) { + printf("osh: failed to open %s\n", pathname); return fd; } - i = 0; + while (read(fd, &c, 1) > 0) { + /* Skip comments */ + if (c == COMMENT) { + script_skip_comment(fd); + continue; + } + + /* Skip blank newlines */ + if (c == '\n' && buf_i == 0) { + continue; + } + + if (buf_i >= sizeof(buf) - 1) { + buf_i = 0; + } + + 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; + buf_i = 0; + continue; + } + buf[buf_i++] = c; + } + + return 0; +} + +int +main(int argc, char **argv) +{ + int found, prog_argc; + int stdout_fd; + char *input, *prog_argv[16], *p; + char c; + + if (argc > 1) { + return open_script(argv[1]); + } + + buf_i = 0; running = 1; found = 0; + bell_fd = open("/dev/beep", O_WRONLY); - prcons(fd, WELCOME); + puts(WELCOME); while (running) { - prcons(fd, PROMPT); + memset(prog_argv, 0, sizeof(prog_argv)); + fputs(PROMPT, stdout); - input = getstr(fd); + input = getstr(); if (input[0] == '\0') { continue; } - argc = parse_args(input, argv, sizeof(argv)); - if (argc == 0) { + prog_argc = parse_args(input, prog_argv, sizeof(prog_argv)); + if (prog_argc == 0) { continue; } - for (i = 0; cmds[i].name != NULL; i++) { - if (strcmp(input, cmds[i].name) == 0) { - cmds[i].func(fd, argc, argv); - found = 1; - break; - } - } - - if (found == 0) { - prcons(fd, "Unrecognized command\n"); - } - + command_match(input, prog_argc, prog_argv, true); found = 0; buf[0] = '\0'; } |