From 78536f9678381885872c9ee47abdf00819161d2a Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 11 Jun 2023 21:01:02 +0300 Subject: [PATCH] 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 --- base/etc/passwd | 2 + kernel/kernel/Process.cpp | 2 - kernel/kernel/kernel.cpp | 2 +- libc/stdio.cpp | 9 -- libc/unistd.cpp | 3 - userspace/CMakeLists.txt | 1 + userspace/init/CMakeLists.txt | 16 ++++ userspace/init/main.cpp | 153 ++++++++++++++++++++++++++++++++++ 8 files changed, 173 insertions(+), 15 deletions(-) create mode 100644 base/etc/passwd create mode 100644 userspace/init/CMakeLists.txt create mode 100644 userspace/init/main.cpp diff --git a/base/etc/passwd b/base/etc/passwd new file mode 100644 index 0000000000..e2c13379c1 --- /dev/null +++ b/base/etc/passwd @@ -0,0 +1,2 @@ +root:x:0:0::/root:/bin/Shell +user:x:1000:1000::/home/user:/bin/Shell diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 6b38f13b81..632e74fd43 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -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; diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index bdf6bae51b..72035ed0ef 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -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( diff --git a/libc/stdio.cpp b/libc/stdio.cpp index d4db1cb343..a151c8edf0 100644 --- a/libc/stdio.cpp +++ b/libc/stdio.cpp @@ -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; diff --git a/libc/unistd.cpp b/libc/unistd.cpp index b7c879d981..a86489f2cd 100644 --- a/libc/unistd.cpp +++ b/libc/unistd.cpp @@ -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) diff --git a/userspace/CMakeLists.txt b/userspace/CMakeLists.txt index 16d090a531..f4deddbf86 100644 --- a/userspace/CMakeLists.txt +++ b/userspace/CMakeLists.txt @@ -5,6 +5,7 @@ project(userspace CXX) set(USERSPACE_PROJECTS cat echo + init ls Shell test diff --git a/userspace/init/CMakeLists.txt b/userspace/init/CMakeLists.txt new file mode 100644 index 0000000000..43f9b7a6d7 --- /dev/null +++ b/userspace/init/CMakeLists.txt @@ -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 +) diff --git a/userspace/init/main.cpp b/userspace/init/main.cpp new file mode 100644 index 0000000000..ea6b37838e --- /dev/null +++ b/userspace/init/main.cpp @@ -0,0 +1,153 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +struct User +{ + BAN::String name; + uid_t uid; + gid_t gid; + BAN::String home; + BAN::String shell; +}; + +BAN::Optional 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 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 parse_users() +{ + FILE* fp = fopen("/etc/passwd", "r"); + if (fp == nullptr) + { + fprintf(stderr, "could not open /etc/passwd\n"); + perror("fopen"); + } + + BAN::Vector 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); + } + } + } + + +}