Serenity Operating System
1/*
2 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
3 * Copyright (c) 2022, Tim Schumacher <timschumi@gmx.de>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <AK/LexicalPath.h>
9#include <LibMain/Main.h>
10#include <Userland/Shell/Shell.h>
11
12#define ENUMERATE_UTILITIES(E) \
13 E(cat) \
14 E(checksum) \
15 E(chmod) \
16 E(chown) \
17 E(cp) \
18 E(df) \
19 E(env) \
20 E(file) \
21 E(find) \
22 E(id) \
23 E(less) \
24 E(ln) \
25 E(ls) \
26 E(lsblk) \
27 E(mkdir) \
28 E(mknod) \
29 E(mount) \
30 E(mv) \
31 E(ps) \
32 E(rm) \
33 E(sh) \
34 E(rmdir) \
35 E(tail) \
36 E(tree) \
37 E(umount) \
38 E(uname) \
39 E(uniq)
40
41// Declare the entrypoints of all the tools that we delegate to.
42// Relying on `decltype(serenity_main)` ensures that we always stay consistent with the `serenity_main` signature.
43#define DECLARE_ENTRYPOINT(name) decltype(serenity_main) name##_main;
44ENUMERATE_UTILITIES(DECLARE_ENTRYPOINT)
45#undef DECLARE_ENTRYPOINT
46
47static void fail()
48{
49 out(stderr, "Direct running of BuggieBox was detected without finding a proper requested utility.\n");
50 out(stderr, "The following programs are supported: uname, env, lsblk, file, df, mount, umount, mkdir, ");
51 out(stderr, "rmdir, rm, chown, chmod, cp, ln, ls, mv, cat, md5sum, sha1sum, sha256sum, sha512sum, sh, uniq, id, tail, ");
52 out(stderr, "find, less, mknod, ps\n");
53 out(stderr, "To use one of these included utilities, create a symbolic link with the target being this binary, and ensure the basename");
54 out(stderr, "is included within.\n");
55}
56
57struct Runner {
58 StringView name;
59 ErrorOr<int> (*func)(Main::Arguments arguments) = nullptr;
60};
61
62static constexpr Runner s_runners[] = {
63#define RUNNER_ENTRY(name) { #name##sv, name##_main },
64 ENUMERATE_UTILITIES(RUNNER_ENTRY)
65#undef RUNNER_ENTRY
66
67 // Some tools have additional aliases.
68 { "md5sum"sv, checksum_main },
69 { "sha1sum"sv, checksum_main },
70 { "sha256sum"sv, checksum_main },
71 { "sha512sum"sv, checksum_main },
72 { "Shell"sv, sh_main },
73};
74
75static ErrorOr<int> run_program(Main::Arguments arguments, LexicalPath const& runbase, bool& found_runner)
76{
77 for (auto& runner : s_runners) {
78 if (runbase.basename() == runner.name) {
79 found_runner = true;
80 return runner.func(arguments);
81 }
82 }
83 return 0;
84}
85
86static ErrorOr<int> buggiebox_main(Main::Arguments arguments)
87{
88 if (arguments.argc == 0) {
89 fail();
90 return 1;
91 }
92 bool found_runner = false;
93 LexicalPath runbase { arguments.strings[0] };
94 auto result = TRY(run_program(arguments, runbase, found_runner));
95 if (!found_runner)
96 fail();
97 return result;
98}
99
100ErrorOr<int> serenity_main(Main::Arguments arguments)
101{
102 LexicalPath runbase { arguments.strings[0] };
103 if (runbase.basename() == "BuggieBox"sv) {
104 Main::Arguments utility_arguments = arguments;
105 utility_arguments.argc--;
106 utility_arguments.argv++;
107 utility_arguments.strings = arguments.strings.slice(1);
108 return buggiebox_main(utility_arguments);
109 }
110 return buggiebox_main(arguments);
111}