#include #include #include #include #include #include #include #include #include #include #include #include #include #include using os::File; static Result> split_command_into_args(StringView cmd) { return cmd.split(" \n"_sv); } static Result execute_command(StringView command) { if (strcspn(command.chars(), " #") == 0) return {}; auto args = TRY(split_command_into_args(command)); if (args.size() < 1) exit(0); return os::Process::exec(args[0].view(), args.slice()); } struct utsname g_sysinfo; const char* hostname = ""; const char* username = ""; char prompt_end = '$'; Result luna_main(int argc, char** argv) { StringView path; StringView command; bool interactive { false }; SharedPtr input_file; os::ArgumentParser parser; parser.add_description("The Luna system's command shell."_sv); parser.add_system_program_info("sh"_sv); parser.add_positional_argument(path, "path"_sv, "-"_sv); parser.add_value_argument(command, 'c', "command"_sv, true, "execute a single command and then exit"_sv); parser.parse(argc, argv); if (!command.is_empty()) TRY(execute_command(command)); if (path == "-") { input_file = File::standard_input(); interactive = true; } else { input_file = TRY(File::open(path, File::ReadOnly)); input_file->set_close_on_exec(); } if (interactive) { // Set up everything to form a prompt. uname(&g_sysinfo); hostname = g_sysinfo.nodename; if (getuid() == 0) prompt_end = '#'; struct passwd* pw = getpwuid(getuid()); if (pw) { username = pw->pw_name; } else { username = getenv("USER"); } endpwent(); } while (1) { if (interactive) { auto cwd = TRY(os::FileSystem::working_directory()); os::print("%s@%s:%s%c ", username, hostname, cwd.chars(), prompt_end); } auto cmd = TRY(input_file->read_line()); if (cmd.is_empty()) { if (interactive) puts("exit"); break; } if (strspn(cmd.chars(), " \n") == cmd.length()) continue; if (strcspn(cmd.chars(), " #") == 0) continue; if (!strncmp(cmd.chars(), "cd", 2)) { auto args = TRY(split_command_into_args(cmd.view())); check(args[0].view() == "cd"); if (args.size() == 1) { auto home = TRY(os::FileSystem::home_directory()); TRY(os::FileSystem::change_directory(home.view())); continue; } TRY(os::FileSystem::change_directory(args[1].view())); continue; } pid_t child = TRY(os::Process::fork()); if (child == 0) { TRY(execute_command(cmd.view())); } TRY(os::Process::wait(child, nullptr)); } return 0; }