#include #include #include #include #include #include #include #include #include #include #include #include using os::File; static Result> split_command_into_argv(StringView cmd, char** out) { char* str = strdup(cmd.chars()); Vector result; char* segment = strtok(str, " \n"); TRY(result.try_append(segment)); if (segment == NULL) return result; for (;;) { segment = strtok(NULL, " \n"); TRY(result.try_append(segment)); if (segment == NULL) return result; } if (out) *out = str; return result; } [[noreturn]] static void execute_command(StringView command) { Vector argv; bool ok = split_command_into_argv(command, nullptr).try_move_value_or_error(argv, errno); if (!ok) { perror("failed to parse command"); exit(1); } if (argv[0] == NULL) exit(0); execvp(argv[0], argv.data()); perror(argv[0]); exit(1); } Result luna_main(int argc, char** argv) { StringView path; StringView command; bool interactive { false }; SharedPtr input_file; os::ArgumentParser parser; parser.add_positional_argument(path, "path"_sv, "-"_sv); parser.add_value_argument(command, 'c', "command"_sv, true); parser.parse(argc, argv); if (!command.is_empty()) 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(); } while (1) { if (interactive) { auto cwd = TRY(os::FileSystem::working_directory()); printf("sh %s%c ", cwd.chars(), getuid() == 0 ? '#' : '$'); } auto cmd = TRY(input_file->read_line()); if (cmd.is_empty()) break; if (strspn(cmd.chars(), " \n") == cmd.length()) continue; if (!strncmp(cmd.chars(), "cd", 2)) { char* copy = nullptr; auto args = TRY(split_command_into_argv(cmd.view(), ©)); check("cd"_sv == args[0]); if (args.size() == 2) { auto home = TRY(os::FileSystem::home_directory()); if (chdir(home.chars()) < 0) perror("cd"); free(copy); continue; } if (chdir(args[1]) < 0) perror("cd"); free(copy); continue; } pid_t child = fork(); if (child < 0) { perror("fork"); return 1; } if (child == 0) { execute_command(cmd.view()); } if (waitpid(child, NULL, 0) < 0) { perror("waitpid"); return 1; } } return 0; }