Kernel/Userspace: Add basic init process
This process parses /etc/passwd and promps login screen. When an username is entered, it will launch that users shell
This commit is contained in:
		
							parent
							
								
									a0be415e09
								
							
						
					
					
						commit
						51eb44bf40
					
				|  | @ -0,0 +1,2 @@ | |||
| root:x:0:0::/root:/bin/Shell | ||||
| user:x:1000:1000::/home/user:/bin/Shell | ||||
|  | @ -300,8 +300,6 @@ namespace Kernel | |||
| 			delete range; | ||||
| 		m_mapped_ranges.clear(); | ||||
| 
 | ||||
| 		m_open_files.clear(); | ||||
| 
 | ||||
| 		load_elf_to_memory(*elf); | ||||
| 
 | ||||
| 		m_userspace_info.entry = elf->file_header_native().e_entry; | ||||
|  |  | |||
|  | @ -180,7 +180,7 @@ static void init2(void* tty1) | |||
| 
 | ||||
| 	((TTY*)tty1)->initialize_device(); | ||||
| 
 | ||||
| 	MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/Shell"sv)); | ||||
| 	MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"sv)); | ||||
| 	return; | ||||
| 
 | ||||
| 	Process::create_kernel( | ||||
|  |  | |||
|  | @ -27,15 +27,6 @@ FILE* stdin  = &s_files[0]; | |||
| FILE* stdout = &s_files[1]; | ||||
| FILE* stderr = &s_files[2]; | ||||
| 
 | ||||
| extern "C" void _init_stdio() | ||||
| { | ||||
| 	char tty[L_ctermid]; | ||||
| 	ctermid(tty); | ||||
| 	if (open(tty, O_RDONLY) != 0) _exit(1); | ||||
| 	if (open(tty, O_WRONLY) != 1) _exit(1); | ||||
| 	if (open(tty, O_WRONLY) != 2) _exit(1); | ||||
| } | ||||
| 
 | ||||
| void clearerr(FILE* file) | ||||
| { | ||||
| 	file->eof = false; | ||||
|  |  | |||
|  | @ -11,12 +11,9 @@ | |||
| 
 | ||||
| char** environ; | ||||
| 
 | ||||
| extern "C" void _init_stdio(); | ||||
| 
 | ||||
| extern "C" void _init_libc(char** _environ) | ||||
| { | ||||
| 	environ = _environ; | ||||
| 	_init_stdio(); | ||||
| } | ||||
| 
 | ||||
| void _exit(int status) | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ project(userspace CXX) | |||
| set(USERSPACE_PROJECTS | ||||
| 	cat | ||||
| 	echo | ||||
| 	init | ||||
| 	ls | ||||
| 	Shell | ||||
| 	test | ||||
|  |  | |||
|  | @ -0,0 +1,16 @@ | |||
| cmake_minimum_required(VERSION 3.26) | ||||
| 
 | ||||
| project(init CXX) | ||||
| 
 | ||||
| set(SOURCES | ||||
| 	main.cpp | ||||
| ) | ||||
| 
 | ||||
| add_executable(init ${SOURCES}) | ||||
| target_compile_options(init PUBLIC -O2 -g) | ||||
| target_link_libraries(init PUBLIC libc ban) | ||||
| 
 | ||||
| add_custom_target(init-install | ||||
| 	COMMAND cp ${CMAKE_CURRENT_BINARY_DIR}/init ${BANAN_BIN}/ | ||||
| 	DEPENDS init | ||||
| ) | ||||
|  | @ -0,0 +1,153 @@ | |||
| #include <BAN/String.h> | ||||
| #include <BAN/Optional.h> | ||||
| #include <BAN/Vector.h> | ||||
| 
 | ||||
| #include <ctype.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| struct User | ||||
| { | ||||
| 	BAN::String name; | ||||
| 	uid_t uid; | ||||
| 	gid_t gid; | ||||
| 	BAN::String home; | ||||
| 	BAN::String shell; | ||||
| }; | ||||
| 
 | ||||
| BAN::Optional<id_t> parse_id(BAN::StringView value) | ||||
| { | ||||
| 	// NOTE: we only allow 10^9 uids
 | ||||
| 	if (value.size() < 1 || value.size() > 9) | ||||
| 		return {}; | ||||
| 
 | ||||
| 	id_t id { 0 }; | ||||
| 	for (char c : value) | ||||
| 	{ | ||||
| 		if (!isdigit(c)) | ||||
| 			return {}; | ||||
| 		id = (id * 10) + (c - '0'); | ||||
| 	} | ||||
| 
 | ||||
| 	return id; | ||||
| } | ||||
| 
 | ||||
| BAN::Optional<User> parse_user(BAN::StringView line) | ||||
| { | ||||
| 	auto parts = MUST(line.split(':', true)); | ||||
| 	if (parts.size() != 7) | ||||
| 		return {}; | ||||
| 	User user; | ||||
| 	user.name = parts[0]; | ||||
| 	user.uid = ({ auto id = parse_id(parts[2]); if (!id.has_value()) return {}; id.value(); }); | ||||
| 	user.gid = ({ auto id = parse_id(parts[3]); if (!id.has_value()) return {}; id.value(); }); | ||||
| 	user.home = parts[5]; | ||||
| 	user.shell = parts[6]; | ||||
| 	return user; | ||||
| } | ||||
| 
 | ||||
| BAN::Vector<User> parse_users() | ||||
| { | ||||
| 	FILE* fp = fopen("/etc/passwd", "r"); | ||||
| 	if (fp == nullptr) | ||||
| 	{ | ||||
| 		fprintf(stderr, "could not open /etc/passwd\n"); | ||||
| 		perror("fopen"); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::Vector<User> users; | ||||
| 
 | ||||
| 	char buffer[1024]; | ||||
| 	while (fgets(buffer, sizeof(buffer), fp)) | ||||
| 	{ | ||||
| 		*strchrnul(buffer, '\n') = '\0'; | ||||
| 		auto user = parse_user(buffer); | ||||
| 		if (user.has_value()) | ||||
| 			MUST(users.push_back(user.release_value())); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ferror(fp)) | ||||
| 	{ | ||||
| 		perror("fread"); | ||||
| 		fclose(fp); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	fclose(fp); | ||||
| 
 | ||||
| 	return users; | ||||
| } | ||||
| 
 | ||||
| void initialize_stdio() | ||||
| { | ||||
| 	char tty[L_ctermid]; | ||||
| 	ctermid(tty); | ||||
| 	if (open(tty, O_RDONLY) != 0) _exit(1); | ||||
| 	if (open(tty, O_WRONLY) != 1) _exit(1); | ||||
| 	if (open(tty, O_WRONLY) != 2) _exit(1); | ||||
| } | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
| 	initialize_stdio(); | ||||
| 
 | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		auto users = parse_users(); | ||||
| 
 | ||||
| 		char name_buffer[128]; | ||||
| 		BAN::StringView name; | ||||
| 
 | ||||
| 		while (true) | ||||
| 		{ | ||||
| 			printf("username: "); | ||||
| 			fflush(stdout); | ||||
| 
 | ||||
| 			size_t nread = fread(name_buffer, 1, sizeof(name_buffer) - 1, stdin); | ||||
| 			if (nread == 0) | ||||
| 			{ | ||||
| 				if (ferror(stdin)) | ||||
| 				{ | ||||
| 					fprintf(stderr, "Could not read from stdin\n"); | ||||
| 					return 1; | ||||
| 				} | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (nread == 1) | ||||
| 				continue;		 | ||||
| 
 | ||||
| 			name = BAN::StringView(name_buffer, nread - 1); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		for (const User& user : users) | ||||
| 		{ | ||||
| 			if (user.name == name) | ||||
| 			{ | ||||
| 				pid_t pid = fork(); | ||||
| 				if (pid == 0) | ||||
| 				{ | ||||
| 					printf("Welcome back %s!\n", user.name.data()); | ||||
| 
 | ||||
| 					execl(user.shell.data(), user.shell.data(), nullptr); | ||||
| 					perror("execl"); | ||||
| 					 | ||||
| 					exit(1); | ||||
| 				} | ||||
| 				 | ||||
| 				if (pid == -1) | ||||
| 				{ | ||||
| 					perror("fork"); | ||||
| 					break; | ||||
| 				} | ||||
| 
 | ||||
| 				int status; | ||||
| 				waitpid(pid, &status, 0); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue