408 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			408 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| 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 <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;
 | |
| }
 |