/* * Copyright (c) 2022, Liav A. * Copyright (c) 2022, Tim Schumacher * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #define ENUMERATE_UTILITIES(E, ALIAS) \ ALIAS(b2sum, checksum) \ E(cat) \ E(checksum) \ E(chmod) \ E(chown) \ E(cp) \ E(df) \ E(env) \ E(file) \ E(find) \ E(id) \ E(less) \ E(ln) \ E(ls) \ E(lsblk) \ ALIAS(md5sum, checksum) \ E(mkdir) \ E(mknod) \ E(mount) \ E(mv) \ E(ps) \ E(rm) \ E(rmdir) \ E(sh) \ ALIAS(sha1sum, checksum) \ ALIAS(sha256sum, checksum) \ ALIAS(sha512sum, checksum) \ ALIAS(Shell, sh) \ E(tail) \ E(tree) \ E(umount) \ E(uname) \ E(uniq) // Declare the entrypoints of all the tools that we delegate to. // Some tools have additional aliases that we skip in the declarations. // Relying on `decltype(serenity_main)` ensures that we always stay consistent with the `serenity_main` signature. #define DECLARE_ENTRYPOINT(name) decltype(serenity_main) name##_main; #define SKIP(alias, name) ENUMERATE_UTILITIES(DECLARE_ENTRYPOINT, SKIP) #undef DECLARE_ENTRYPOINT #undef SKIP static void fail() { #define TOOL_NAME(name) #name##sv, #define ALIAS_NAME(alias, name) #alias##sv, auto const tool_names = { ENUMERATE_UTILITIES(TOOL_NAME, ALIAS_NAME) }; #undef TOOL_NAME #undef ALIAS_NAME outln(stderr); outln(stderr, "Usage:"); outln(stderr, "* Specify a utility as an argument:"); outln(stderr, " $ BuggieBox UTILITY"); outln(stderr, "* Create a symbolic link with the target being this binary,"); outln(stderr, " and ensure the basename is one of the supported utilities' name."); outln(stderr); outln(stderr, "The following utilities are supported:"); int count = 0; for (auto const& tool_name : tool_names) { if (++count % 5 == 1) out(stderr, "\n\t"); out(stderr, "{:12}", tool_name); } outln(stderr); } struct Runner { StringView name; ErrorOr (*func)(Main::Arguments arguments) = nullptr; }; static constexpr Runner s_runners[] = { #define RUNNER_ENTRY(name) { #name##sv, name##_main }, #define ALIAS_RUNNER_ENTRY(alias, name) { #alias##sv, name##_main }, ENUMERATE_UTILITIES(RUNNER_ENTRY, ALIAS_RUNNER_ENTRY) #undef RUNNER_ENTRY #undef ALIAS_RUNNER_ENTRY }; static ErrorOr run_program(Main::Arguments arguments, LexicalPath const& runbase, bool& found_runner) { for (auto& runner : s_runners) { if (runbase.basename() == runner.name) { found_runner = true; return runner.func(arguments); } } return 0; } static ErrorOr buggiebox_main(Main::Arguments arguments) { if (arguments.argc == 0) { outln(stderr, "Detected directly running BuggieBox without specifying a utility."); fail(); return 1; } bool found_runner = false; LexicalPath runbase { arguments.strings[0] }; auto result = TRY(run_program(arguments, runbase, found_runner)); if (!found_runner) { outln(stderr, "'{}' is not supported by BuggieBox.", runbase); fail(); } return result; } ErrorOr serenity_main(Main::Arguments arguments) { LexicalPath runbase { arguments.strings[0] }; if (runbase.basename() == "BuggieBox"sv) { Main::Arguments utility_arguments = arguments; utility_arguments.argc--; utility_arguments.argv++; utility_arguments.strings = arguments.strings.slice(1); return buggiebox_main(utility_arguments); } return buggiebox_main(arguments); }