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