Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
parent
886521714f
commit
6f0e1924df
407
kernel/kshell.c
Normal file
407
kernel/kshell.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
Copyright (C) 2016-2019 The University of Notre Dame
|
||||
This software is distributed under the GNU General Public License.
|
||||
See the file LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/error.h"
|
||||
#include "kernel/ascii.h"
|
||||
#include "kshell.h"
|
||||
#include "console.h"
|
||||
#include "string.h"
|
||||
#include "rtc.h"
|
||||
#include "kmalloc.h"
|
||||
#include "page.h"
|
||||
#include "process.h"
|
||||
#include "main.h"
|
||||
#include "fs.h"
|
||||
#include "syscall_handler.h"
|
||||
#include "clock.h"
|
||||
#include "kernelcore.h"
|
||||
#include "bcache.h"
|
||||
#include "printf.h"
|
||||
|
||||
static int kshell_mount( const char *devname, int unit, const char *fs_type)
|
||||
{
|
||||
if(current->ktable[KNO_STDDIR]) {
|
||||
printf("root filesystem already mounted, please unmount first\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct device *dev = device_open(devname,unit);
|
||||
if(dev) {
|
||||
struct fs *fs = fs_lookup(fs_type);
|
||||
if(fs) {
|
||||
struct fs_volume *v = fs_volume_open(fs,dev);
|
||||
if(v) {
|
||||
struct fs_dirent *d = fs_volume_root(v);
|
||||
if(d) {
|
||||
current->ktable[KNO_STDDIR] = kobject_create_dir(d);
|
||||
return 0;
|
||||
} else {
|
||||
printf("mount: couldn't find root dir on %s unit %d!\n",device_name(dev),device_unit(dev));
|
||||
return -1;
|
||||
}
|
||||
fs_volume_close(v);
|
||||
} else {
|
||||
printf("mount: couldn't mount %s on %s unit %d\n",fs_type,device_name(dev),device_unit(dev));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("mount: invalid fs type: %s\n", fs_type);
|
||||
return -1;
|
||||
}
|
||||
device_close(dev);
|
||||
} else {
|
||||
printf("mount: couldn't open device %s unit %d\n",devname,unit);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int kshell_automount()
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<4;i++) {
|
||||
printf("automount: trying atapi unit %d...\n",i);
|
||||
if(kshell_mount("atapi",i,"cdromfs")==0) return 0;
|
||||
}
|
||||
|
||||
for(i=0;i<4;i++) {
|
||||
printf("automount: trying ata unit %d...\n",i);
|
||||
if(kshell_mount("ata",i,"simplefs")==0) return 0;
|
||||
}
|
||||
|
||||
printf("automount: no bootable devices available.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Install software from the cdrom volume unit src
|
||||
to the disk volume dst by performing a recursive copy.
|
||||
XXX This needs better error checking.
|
||||
*/
|
||||
|
||||
int kshell_install( const char *src_device_name, int src_unit, const char *dst_device_name, int dst_unit )
|
||||
{
|
||||
struct fs *srcfs = fs_lookup("cdromfs");
|
||||
struct fs *dstfs = fs_lookup("diskfs");
|
||||
|
||||
if(!srcfs || !dstfs) return KERROR_NOT_FOUND;
|
||||
|
||||
struct device *srcdev = device_open(src_device_name,src_unit);
|
||||
struct device *dstdev = device_open(dst_device_name,dst_unit);
|
||||
|
||||
if(!srcdev || !dstdev) return KERROR_NOT_FOUND;
|
||||
|
||||
struct fs_volume *srcvolume = fs_volume_open(srcfs,srcdev);
|
||||
struct fs_volume *dstvolume = fs_volume_open(dstfs,dstdev);
|
||||
|
||||
if(!srcvolume || !dstvolume) return KERROR_NOT_FOUND;
|
||||
|
||||
struct fs_dirent *srcroot = fs_volume_root(srcvolume);
|
||||
struct fs_dirent *dstroot = fs_volume_root(dstvolume);
|
||||
|
||||
printf("copying %s unit %d to %s unit %d...\n",src_device_name,src_unit,dst_device_name,dst_unit);
|
||||
|
||||
fs_dirent_copy(srcroot, dstroot,0);
|
||||
|
||||
fs_dirent_close(dstroot);
|
||||
fs_dirent_close(srcroot);
|
||||
|
||||
fs_volume_close(srcvolume);
|
||||
fs_volume_close(dstvolume);
|
||||
|
||||
device_close(srcdev);
|
||||
|
||||
bcache_flush_device(dstdev);
|
||||
device_close(dstdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kshell_printdir(const char *d, int length)
|
||||
{
|
||||
while(length > 0) {
|
||||
printf("%s\n", d);
|
||||
int len = strlen(d) + 1;
|
||||
d += len;
|
||||
length -= len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kshell_listdir(const char *path)
|
||||
{
|
||||
struct fs_dirent *d = fs_resolve(path);
|
||||
if(d) {
|
||||
int buffer_length = 1024;
|
||||
char *buffer = kmalloc(buffer_length);
|
||||
if(buffer) {
|
||||
int length = fs_dirent_list(d, buffer, buffer_length);
|
||||
if(length>=0) {
|
||||
kshell_printdir(buffer, length);
|
||||
} else {
|
||||
printf("list: %s is not a directory\n", path);
|
||||
}
|
||||
kfree(buffer);
|
||||
}
|
||||
} else {
|
||||
printf("list: %s does not exist\n", path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kshell_execute(int argc, const char **argv)
|
||||
{
|
||||
const char *cmd = argv[0];
|
||||
|
||||
if(!strcmp(cmd, "start")) {
|
||||
if(argc > 1) {
|
||||
int fd = sys_open_file(KNO_STDDIR,argv[1],0,0);
|
||||
if(fd>=0) {
|
||||
int pid = sys_process_run(fd, argc - 1, &argv[1]);
|
||||
if(pid > 0) {
|
||||
printf("started process %d\n", pid);
|
||||
process_yield();
|
||||
} else {
|
||||
printf("couldn't start %s\n", argv[1]);
|
||||
}
|
||||
sys_object_close(fd);
|
||||
} else {
|
||||
printf("couldn't find %s\n",argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("run: requires argument.\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "exec")) {
|
||||
if(argc > 1) {
|
||||
int fd = sys_open_file(KNO_STDDIR,argv[1],0,0);
|
||||
if(fd>=0) {
|
||||
sys_process_exec(fd, argc - 1, &argv[1]);
|
||||
process_yield();
|
||||
printf("couldn't exec %s\n", argv[1]);
|
||||
} else {
|
||||
printf("couldn't find %s\n",argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("exec: requires argument.\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "run")) {
|
||||
if(argc > 1) {
|
||||
int fd = sys_open_file(KNO_STDDIR,argv[1],0,0);
|
||||
if(fd>=0) {
|
||||
int pid = sys_process_run(fd, argc - 1, &argv[1]);
|
||||
if(pid > 0) {
|
||||
printf("started process %d\n", pid);
|
||||
process_yield();
|
||||
struct process_info info;
|
||||
process_wait_child(pid, &info, -1);
|
||||
printf("process %d exited with status %d\n", info.pid, info.exitcode);
|
||||
process_reap(info.pid);
|
||||
} else {
|
||||
printf("couldn't start %s\n", argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("couldn't find %s\n",argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("run: requires argument\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "automount")) {
|
||||
kshell_automount();
|
||||
} else if(!strcmp(cmd, "mount")) {
|
||||
if(argc==4) {
|
||||
int unit;
|
||||
if(str2int(argv[2], &unit)) {
|
||||
kshell_mount(argv[1],unit,argv[3]);
|
||||
} else {
|
||||
printf("mount: expected unit number but got %s\n", argv[2]);
|
||||
}
|
||||
} else {
|
||||
printf("mount: requires device, unit, and fs type\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "umount")) {
|
||||
if(current->ktable[KNO_STDDIR]) {
|
||||
printf("unmounting root directory\n");
|
||||
sys_object_close(KNO_STDDIR);
|
||||
} else {
|
||||
printf("nothing currently mounted\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "reap")) {
|
||||
if(argc > 1) {
|
||||
int pid;
|
||||
if(str2int(argv[1], &pid)) {
|
||||
if(process_reap(pid)) {
|
||||
printf("reap failed!\n");
|
||||
} else {
|
||||
printf("process %d reaped\n", pid);
|
||||
}
|
||||
} else {
|
||||
printf("reap: expected process id but got %s\n", argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("reap: requires argument\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "kill")) {
|
||||
if(argc > 1) {
|
||||
int pid;
|
||||
if(str2int(argv[1], &pid)) {
|
||||
process_kill(pid);
|
||||
} else {
|
||||
printf("kill: expected process id number but got %s\n", argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("kill: requires argument\n");
|
||||
}
|
||||
|
||||
} else if(!strcmp(cmd, "wait")) {
|
||||
struct process_info info;
|
||||
if(process_wait_child(0, &info, 5000) > 0) {
|
||||
printf("process %d exited with status %d\n", info.pid, info.exitcode);
|
||||
} else {
|
||||
printf("wait: timeout\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "list")) {
|
||||
if(argc > 1) {
|
||||
kshell_listdir(argv[1]);
|
||||
} else {
|
||||
kshell_listdir(".");
|
||||
}
|
||||
} else if(!strcmp(cmd, "mkdir")) {
|
||||
if(argc == 3) {
|
||||
struct fs_dirent *dir = fs_resolve(argv[1]);
|
||||
if(dir) {
|
||||
struct fs_dirent *n = fs_dirent_mkdir(dir,argv[2]);
|
||||
if(!n) {
|
||||
printf("mkdir: couldn't create %s\n",argv[2]);
|
||||
} else {
|
||||
fs_dirent_close(n);
|
||||
}
|
||||
fs_dirent_close(dir);
|
||||
} else {
|
||||
printf("mkdir: couldn't open %s\n",argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("use: mkdir <parent-dir> <dirname>\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "format")) {
|
||||
if(argc == 4) {
|
||||
int unit;
|
||||
if(str2int(argv[2], &unit)) {
|
||||
struct fs *f = fs_lookup(argv[3]);
|
||||
if(f) {
|
||||
struct device *d = device_open(argv[1],unit);
|
||||
if(d) {
|
||||
fs_volume_format(f,d);
|
||||
} else {
|
||||
printf("couldn't open device %s unit %d\n",argv[1],unit);
|
||||
}
|
||||
} else {
|
||||
printf("invalid fs type: %s\n", argv[3]);
|
||||
}
|
||||
} else {
|
||||
printf("format: expected unit number but got %s\n", argv[2]);
|
||||
}
|
||||
}
|
||||
} else if(!strcmp(cmd,"install")) {
|
||||
if(argc==5) {
|
||||
int src, dst;
|
||||
str2int(argv[2], &src);
|
||||
str2int(argv[4], &dst);
|
||||
kshell_install(argv[1],src,argv[3],dst);
|
||||
} else {
|
||||
printf("install: expected src-device-name src-unit dest-device-name dest-unit\n");
|
||||
}
|
||||
|
||||
} else if(!strcmp(cmd, "remove")) {
|
||||
if(argc == 3) {
|
||||
struct fs_dirent *dir = fs_resolve(argv[1]);
|
||||
if(dir) {
|
||||
int result = fs_dirent_remove(dir,argv[2]);
|
||||
if(result<0) {
|
||||
printf("remove: couldn't remove %s\n",argv[2]);
|
||||
}
|
||||
fs_dirent_close(dir);
|
||||
} else {
|
||||
printf("remove: couldn't open %s\n",argv[1]);
|
||||
}
|
||||
} else {
|
||||
printf("use: remove <parent-dir> <filename>\n");
|
||||
}
|
||||
} else if(!strcmp(cmd, "time")) {
|
||||
struct rtc_time time;
|
||||
rtc_read(&time);
|
||||
printf("%d-%d-%d %d:%d:%d\n", time.year, time.month, time.day, time.hour, time.minute, time.second);
|
||||
} else if(!strcmp(cmd, "reboot")) {
|
||||
reboot();
|
||||
} else if(!strcmp(cmd, "bcache_stats")) {
|
||||
struct bcache_stats stats;
|
||||
bcache_get_stats(&stats);
|
||||
printf("%d rhit %d rmiss %d whit %d wmiss %d wback\n",
|
||||
stats.read_hits,stats.read_misses,
|
||||
stats.write_hits,stats.write_misses,
|
||||
stats.writebacks);
|
||||
} else if(!strcmp(cmd,"bcache_flush")) {
|
||||
bcache_flush_all();
|
||||
} else if(!strcmp(cmd, "help")) {
|
||||
printf("Kernel Shell Commands:\nrun <path> <args>\nstart <path> <args>\nkill <pid>\nreap <pid>\nwait\nlist\nautomount\nmount <device> <unit> <fstype>\numount\nformat <device> <unit><fstype>\ninstall atapi <srcunit> ata <dstunit>\nmkdir <path>\nremove <path>time\nbcache_stats\nbcache_flush\nreboot\nhelp\n\n");
|
||||
} else {
|
||||
printf("%s: command not found\n", argv[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kshell_readline(char *line, int length)
|
||||
{
|
||||
int i = 0;
|
||||
while(i < (length - 1)) {
|
||||
char c = console_getchar(&console_root);
|
||||
if(c == ASCII_CR) {
|
||||
line[i] = 0;
|
||||
printf("\n");
|
||||
return 1;
|
||||
} else if(c == ASCII_BS) {
|
||||
if(i > 0) {
|
||||
putchar(c);
|
||||
i--;
|
||||
}
|
||||
} else if(c >= 0x20 && c <= 0x7E) {
|
||||
putchar(c);
|
||||
line[i] = c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int kshell_launch()
|
||||
{
|
||||
char line[1024];
|
||||
const char *argv[100];
|
||||
int argc;
|
||||
|
||||
while(1) {
|
||||
printf("kshell> ");
|
||||
kshell_readline(line, sizeof(line));
|
||||
|
||||
argc = 0;
|
||||
argv[argc] = strtok(line, " ");
|
||||
while(argv[argc]) {
|
||||
argc++;
|
||||
argv[argc] = strtok(0, " ");
|
||||
}
|
||||
|
||||
if(argc > 0) {
|
||||
kshell_execute(argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user