/* 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; } 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 \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 \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 \nstart \nkill \nreap \nwait\nlist\nautomount\nmount \numount\nformat \ninstall atapi ata \nmkdir \nremove 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; }