#include "Command.h" #include "Prompt.h" #include "sh.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using os::File; // Do nothing, but we need a handler so read() returns EINTR. static void sigint_handler(int) { } static Result execute_loop(bool interactive, SharedPtr input_file) { while (1) { if (interactive) display_prompt(); auto maybe_cmd = TRY(read_command(input_file)); if (!maybe_cmd.has_value()) { if (interactive) puts("exit"); break; } auto cmd = maybe_cmd.release_value(); if (cmd.is_empty()) continue; auto command = TRY(parse_command(cmd.view())); if (command->args.size() < 1) continue; TRY(execute_command_in_subprocess(move(command), input_file, interactive)); } return 0; } Result execute_rc_file() { static const StringView rc_file_name = ".shellrc"_sv; auto home_path = TRY(os::FileSystem::home_directory()); auto home_dir = TRY(os::Directory::open(home_path.view())); auto rc_file_path = os::Path { home_dir->fd(), rc_file_name }; if (os::FileSystem::exists(rc_file_path)) { auto rc_file = TRY(os::File::open(rc_file_path, os::File::ReadOnly)); TRY(execute_loop(false, rc_file)); } return {}; } 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, "execute a single command and then exit"_sv); parser.add_switch_argument(interactive, 'i', "interactive"_sv, "run an interactive shell"_sv); parser.parse(argc, argv); TRY(init_builtins()); if (!command.is_empty()) { auto cmd_obj = TRY(parse_command(command)); execute_command_or_builtin(move(cmd_obj)); } if (path == "-") { input_file = File::standard_input(); } else { input_file = TRY(File::open(path, File::ReadOnly)); input_file->set_close_on_exec(); } if (isatty(input_file->fd())) interactive = true; if (interactive) { setup_prompt(); signal(SIGTTOU, SIG_IGN); signal(SIGINT, sigint_handler); tcsetpgrp(input_file->fd(), getpgid(0)); TRY(execute_rc_file()); } return execute_loop(interactive, input_file); }