toaruos/kernel/core/shell.c

470 lines
12 KiB
C
Raw Normal View History

/*
* vim:tabstop=4
* vim:noexpandtab
*
2011-02-09 04:03:54 +03:00
* ToAruOS Kernel Debugger Shell
*
* Part of the ToAruOS Kernel, under the NCSA license
*
* Copyright 2011 Kevin Lange
*
* (Preliminary documentation based on intended future use; currently,
* this is just a file system explorer)
*
* This is a kernel debugging shell that allows basic, sh-like operation
* of the system while it is in use, without other tasks running in the
* background. While the debug shell is running, the tasker is disabled
* and the kernel will remainin on its current task, allowing users to
* display registry and memory information relavent to the current task.
*
*/
#include <system.h>
#include <fs.h>
#include <multiboot.h>
#include <ata.h>
2011-11-24 07:18:48 +04:00
struct {
char path[1024];
char * username;
char * hostname;
uint16_t month, day, hours, minutes, seconds;
fs_node_t * node;
} shell;
#define SHELL_COMMANDS 512
typedef uint32_t(*shell_command_t) (int argc, char ** argv);
char * shell_commands[SHELL_COMMANDS];
shell_command_t shell_pointers[SHELL_COMMANDS];
uint32_t shell_commands_len = 0;
void
2011-11-24 07:18:48 +04:00
redraw_shell() {
kprintf("\033[1m[\033[1;33m%s \033[1;32m%s \033[1;31m%d/%d \033[1;34m%d:%d:%d\033[0m \033[0m%s\033[1m]\033[0m\n\033[1;32m$\033[0m ",
shell.username, shell.hostname, shell.month, shell.day, shell.hours, shell.minutes, shell.seconds, shell.path);
}
void
init_shell() {
shell.node = fs_root;
shell.username = "kernel";
shell.hostname = "toaru";
shell.path[0] = '/';
shell.path[1] = '\0';
}
void
shell_install_command(char * name, shell_command_t func) {
if (shell_commands_len == SHELL_COMMANDS) {
kprintf("Ran out of space for static shell commands. The maximum number of commands is %d\n", SHELL_COMMANDS);
return;
}
shell_commands[shell_commands_len] = name;
shell_pointers[shell_commands_len] = func;
shell_commands_len++;
}
shell_command_t shell_find(char * str) {
for (uint32_t i = 0; i < shell_commands_len; ++i) {
if (!strcmp(str, shell_commands[i])) {
return shell_pointers[i];
}
}
return NULL;
}
void shell_update_time() {
get_date(&shell.month, &shell.day);
get_time(&shell.hours, &shell.minutes, &shell.seconds);
}
void shell_exec(char * buffer, int size) {
/*
* Tokenize the command
*/
char * pch;
char * cmd;
char * save;
pch = strtok_r(buffer," ",&save);
cmd = pch;
if (!cmd) { return; }
char * argv[1024]; /* Command tokens (space-separated elements) */
int tokenid = 0;
while (pch != NULL) {
argv[tokenid] = (char *)pch;
++tokenid;
pch = strtok_r(NULL," ",&save);
}
argv[tokenid] = NULL;
shell_command_t func = shell_find(argv[0]);
if (func) {
func(tokenid, argv);
} else {
/* Alright, here we go */
char * filename = malloc(sizeof(char) * 1024);
fs_node_t * chd = NULL;
if (argv[0][0] == '/') {
memcpy(filename, argv[0], strlen(argv[0]) + 1);
chd = kopen(filename, 0);
}
if (!chd) {
/* Alright, let's try this... */
char * search_path = "/bin/";
memcpy(filename, search_path, strlen(search_path));
memcpy((void*)((uintptr_t)filename + strlen(search_path)),argv[0],strlen(argv[0])+1);
chd = kopen(filename, 0);
}
if (!chd) {
kprintf("Unrecognized command: %s\n", cmd);
} else {
2011-11-24 07:18:48 +04:00
close_fs(chd);
system(filename, tokenid, argv);
}
free(filename);
}
}
uint32_t shell_cmd_cd(int argc, char * argv[]) {
if (argc < 2) {
return 1;
} else {
if (!strcmp(argv[1],".")) {
return 0;
} else {
if (!strcmp(argv[1],"..")) {
char * last_slash = (char *)rfind(shell.path,'/');
if (last_slash == shell.path) {
last_slash[1] = '\0';
} else {
2011-11-24 07:18:48 +04:00
last_slash[0] = '\0';
}
2011-11-24 07:18:48 +04:00
shell.node = kopen(shell.path, 0);
} else {
char * filename = malloc(sizeof(char) * 1024);
if (argv[1][0] == '/') {
memcpy(filename, argv[1], strlen(argv[1]) + 1);
2011-11-18 02:08:20 +04:00
} else {
2011-11-24 07:18:48 +04:00
memcpy(filename, shell.path, strlen(shell.path));
if (!strcmp(shell.path,"/")) {
memcpy((void *)((uintptr_t)filename + strlen(shell.path)),argv[1],strlen(argv[1])+1);
2011-11-02 03:35:09 +04:00
} else {
2011-11-24 07:18:48 +04:00
filename[strlen(shell.path)] = '/';
memcpy((void *)((uintptr_t)filename + strlen(shell.path) + 1),argv[1],strlen(argv[1])+1);
2011-11-02 03:35:09 +04:00
}
2011-02-11 06:45:29 +03:00
}
2011-11-24 07:18:48 +04:00
fs_node_t * chd = kopen(filename, 0);
if (chd) {
if ((chd->flags & FS_DIRECTORY) == 0) {
kprintf("%s: %s is not a directory\n", argv[0], filename);
2011-11-24 07:18:48 +04:00
return 1;
}
2011-11-24 07:18:48 +04:00
shell.node = chd;
memcpy(shell.path, filename, strlen(filename));
shell.path[strlen(filename)] = '\0';
2011-04-09 01:17:36 +04:00
} else {
kprintf("%s: could not change directory\n", argv[0]);
2011-04-09 01:17:36 +04:00
}
}
2011-11-24 07:18:48 +04:00
for (uint32_t i = 0; i <= strlen(shell.path); ++i) {
current_task->wd[i] = shell.path[i];
}
}
}
return 0;
}
uint32_t shell_cmd_info(int argc, char * argv[]) {
if (argc < 2) {
kprintf("%s: Expected argument\n", argv[0]);
2011-11-24 07:18:48 +04:00
return 1;
}
fs_node_t * file = kopen(argv[1], 0);
if (!file) {
kprintf("Could not open file `%s`\n", argv[1]);
return 1;
}
kprintf("flags: 0x%x\n", file->flags);
kprintf("mask: 0x%x\n", file->mask);
kprintf("inode: 0x%x\n", file->inode);
kprintf("uid: %d gid: %d\n", file->uid, file->gid);
kprintf("open(): 0x%x\n", file->open);
kprintf("read(): 0x%x\n", file->read);
kprintf("write(): 0x%x\n", file->write);
if ((file->mask & 0x001) || (file->mask & 0x008) || (file->mask & 0x040)) {
kprintf("File is executable.\n");
}
close_fs(file);
return 0;
}
uint32_t shell_cmd_ls(int argc, char * argv[]) {
/*
* List the files in the current working directory
*/
struct dirent * entry = NULL;
int i = 0;
fs_node_t * ls_node;
char * dir_path;
2011-11-24 07:18:48 +04:00
if (argc < 2) {
ls_node = shell.node;
dir_path = shell.path;
2011-11-24 07:18:48 +04:00
} else {
ls_node = kopen(argv[1], 0);
dir_path = argv[1];
2011-11-24 07:18:48 +04:00
if (!ls_node) {
kprintf("%s: Could not stat directory '%s'.\n", argv[0], argv[1]);
2011-11-24 07:18:48 +04:00
return 1;
}
}
entry = readdir_fs(ls_node, i);
while (entry != NULL) {
char * filename = malloc(sizeof(char) * 1024);
memcpy(filename, dir_path, strlen(dir_path));
if (!strcmp(dir_path,"/")) {
memcpy((void *)((uintptr_t)filename + strlen(dir_path)),entry->name,strlen(entry->name)+1);
2011-11-24 07:18:48 +04:00
} else {
filename[strlen(dir_path)] = '/';
memcpy((void *)((uintptr_t)filename + strlen(dir_path) + 1),entry->name,strlen(entry->name)+1);
2011-11-24 07:18:48 +04:00
}
fs_node_t * chd = kopen(filename, 0);
if (chd) {
if (chd->flags & FS_DIRECTORY) {
kprintf("\033[1;34m");
} else if ((chd->mask & 0x001) || (chd->mask & 0x008) || (chd->mask & 0x040)) {
kprintf("\033[1;32m");
}
close_fs(chd);
}
free(filename);
kprintf("%s\033[0m\n", entry->name);
free(entry);
i++;
entry = readdir_fs(ls_node, i);
}
if (ls_node != shell.node) {
close_fs(ls_node);
}
return 0;
}
uint32_t shell_cmd_out(int argc, char * argv[]) {
if (argc < 3) {
kprintf("Need a port and a character (both as numbers, please) to write...\n");
return 1;
} else {
int port;
port = atoi(argv[1]);
int val;
val = atoi(argv[2]);
kprintf("Writing %d (%c) to port %d\n", val, (unsigned char)val, port);
outportb((short)port, (unsigned char)val);
}
return 0;
}
uint32_t shell_cmd_cpudetect(int argc, char * argv[]) {
detect_cpu();
return 0;
}
uint32_t shell_cmd_multiboot(int argc, char * argv[]) {
dump_multiboot(mboot_ptr);
return 0;
}
uint32_t shell_cmd_screenshot(int argc, char * argv[]) {
if (argc < 2) {
bochs_screenshot(NULL);
} else {
bochs_screenshot(argv[1]);
}
2011-11-24 07:18:48 +04:00
return 0;
}
uint32_t shell_cmd_readsb(int argc, char * argv[]) {
extern void ext2_disk_read_superblock();
ext2_disk_read_superblock();
return 0;
}
uint32_t shell_cmd_readdisk(int argc, char * argv[]) {
uint8_t buf[512] = {1};
uint32_t i = 0;
uint8_t slave = 0;
if (argc >= 2) {
if (!strcmp(argv[1], "slave")) {
slave = 1;
}
}
while (buf[0]) {
ide_read_sector(0x1F0, slave, i, buf);
for (uint16_t j = 0; j < 512; ++j) {
ansi_put(buf[j]);
}
2011-11-24 07:18:48 +04:00
++i;
}
2011-11-24 07:18:48 +04:00
return 0;
}
2011-11-24 07:18:48 +04:00
uint32_t shell_cmd_writedisk(int argc, char * argv[]) {
uint8_t buf[512] = "Hello world!\n";
ide_write_sector(0x1F0, 0, 0x000000, buf);
return 0;
}
#include <ext2.h>
ext2_inodetable_t * ext2_disk_alloc_inode(ext2_inodetable_t * parent, char * name);
uint32_t shell_cmd_testing(int argc, char * argv[]) {
ext2_inodetable_t * derp = ext2_disk_alloc_inode(NULL, "test");
return 0;
}
2011-11-24 07:18:48 +04:00
void install_commands() {
shell_install_command("cd", shell_cmd_cd);
shell_install_command("ls", shell_cmd_ls);
shell_install_command("info", shell_cmd_info);
shell_install_command("out", shell_cmd_out);
shell_install_command("cpu-detect", shell_cmd_cpudetect);
shell_install_command("multiboot", shell_cmd_multiboot);
shell_install_command("screenshot", shell_cmd_screenshot);
shell_install_command("read-sb", shell_cmd_readsb);
shell_install_command("read-disk", shell_cmd_readdisk);
shell_install_command("write-disk", shell_cmd_writedisk);
shell_install_command("test-alloc-block", shell_cmd_testing);
}
void add_path_contents() {
struct dirent * entry = NULL;
int i = 0;
fs_node_t * ls_node;
ls_node = kopen("/bin", 0);
char * dir_path = "/bin";
if (!ls_node) {
kprintf("Failed to open /bin\n");
return;
}
entry = readdir_fs(ls_node, i);
while (entry != NULL) {
char * filename = malloc(sizeof(char) * 1024);
memcpy(filename, dir_path, strlen(dir_path));
filename[strlen(dir_path)] = '/';
memcpy((void *)((uintptr_t)filename + strlen(dir_path) + 1),entry->name,strlen(entry->name)+1);
fs_node_t * chd = kopen(filename, 0);
if (chd) {
if (chd->flags & FS_DIRECTORY) {
} else if ((chd->mask & 0x001) || (chd->mask & 0x008) || (chd->mask & 0x040)) {
char * s = malloc(sizeof(char) * (strlen(entry->name) + 1));
memcpy(s, entry->name, strlen(entry->name) + 1);
shell_install_command(s, NULL);
}
close_fs(chd);
}
free(filename);
free(entry);
i++;
entry = readdir_fs(ls_node, i);
}
if (ls_node != shell.node) {
close_fs(ls_node);
}
}
void tab_complete_shell(char * buffer) {
char buf[1024];
memcpy(buf, buffer, 1024);
char * pch;
char * cmd;
char * save;
pch = strtok_r(buf," ",&save);
cmd = pch;
char * argv[1024]; /* Command tokens (space-separated elements) */
int argc = 0;
if (!cmd) {
argv[0] = "";
argc = 1;
} else {
while (pch != NULL) {
argv[argc] = (char *)pch;
++argc;
pch = strtok_r(NULL," ",&save);
}
}
argv[argc] = NULL;
if (argc < 2) {
if (buffer[strlen(buffer)-1] == ' ' || argc == 0) {
kprintf("\n");
for (uint32_t i = 0; i < shell_commands_len; ++i) {
kprintf(shell_commands[i]);
if (i < shell_commands_len - 1) {
kprintf(", ");
}
}
kprintf("\n");
redraw_shell();
kgets_redraw_buffer();
return;
} else {
uint32_t count = 0, j = 0;
for (uint32_t i = 0; i < shell_commands_len; ++i) {
if (strspn(shell_commands[i], argv[0]) == strlen(argv[0])) {
count++;
}
}
for (uint32_t i = 0; i < shell_commands_len; ++i) {
if (strspn(shell_commands[i], argv[0]) == strlen(argv[0])) {
if (count == 1) {
for (uint32_t j = 0; j < strlen(buffer); ++j) {
kprintf("\x08 \x08");
}
kprintf(shell_commands[i]);
memcpy(buffer, shell_commands[i], strlen(shell_commands[i]) + 1);
return;
}
}
}
kprintf("\n");
for (uint32_t i = 0; i < shell_commands_len; ++i) {
if (strspn(shell_commands[i], argv[0]) == strlen(argv[0])) {
kprintf(shell_commands[i]);
++j;
if (j < count) {
kprintf(", ");
}
}
}
kprintf("\n");
redraw_shell();
kgets_redraw_buffer();
return;
}
} else {
/* Complete path names */
kprintf("%d\n", argc);
}
2011-11-24 07:18:48 +04:00
}
void
start_shell() {
init_shell();
install_commands();
add_path_contents();
2011-11-24 07:18:48 +04:00
while (1) {
/* Read buffer */
shell_update_time();
redraw_shell();
char buffer[1024];
int size;
/* Read commands */
2011-11-24 07:22:25 +04:00
kgets_redraw_func = redraw_shell;
kgets_tab_complete_func = tab_complete_shell;
2011-11-24 07:18:48 +04:00
size = kgets((char *)&buffer, 1023);
if (size < 1) {
continue;
} else {
/* Execute command */
shell_exec(buffer, size);
}
}
}