Serenity Operating System
1/*
2 * Copyright (c) 2022, Samuel Bowman <sam@sambowman.tech>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <Applications/PartitionEditor/PartitionEditorWindowGML.h>
8#include <Applications/PartitionEditor/PartitionModel.h>
9#include <LibCore/DeprecatedFile.h>
10#include <LibCore/Directory.h>
11#include <LibCore/System.h>
12#include <LibGUI/Application.h>
13#include <LibGUI/ComboBox.h>
14#include <LibGUI/ItemListModel.h>
15#include <LibGUI/Menu.h>
16#include <LibGUI/MessageBox.h>
17#include <LibGUI/TableView.h>
18#include <unistd.h>
19
20static Vector<DeprecatedString> get_device_paths()
21{
22 auto device_paths = Vector<DeprecatedString>();
23 // FIXME: Propagate errors.
24 (void)Core::Directory::for_each_entry("/dev"sv, Core::DirIterator::Flags::SkipParentAndBaseDir, [&](auto const& entry, auto const& directory) -> ErrorOr<IterationDecision> {
25 auto full_path = LexicalPath::join(directory.path().string(), entry.name).string();
26 if (Core::DeprecatedFile::is_block_device(full_path))
27 device_paths.append(full_path);
28 return IterationDecision::Continue;
29 });
30 return device_paths;
31}
32
33ErrorOr<int> serenity_main(Main::Arguments arguments)
34{
35 TRY(Core::System::pledge("stdio recvfd sendfd rpath unix"));
36
37 auto app = TRY(GUI::Application::try_create(arguments));
38
39 TRY(Core::System::pledge("stdio recvfd sendfd rpath"));
40 TRY(Core::System::unveil("/dev", "r"));
41 TRY(Core::System::unveil("/res", "r"));
42 TRY(Core::System::unveil(nullptr, nullptr));
43
44 auto app_icon = TRY(GUI::Icon::try_create_default_icon("app-partition-editor"sv));
45
46 auto window = TRY(GUI::Window::try_create());
47 window->set_title("Partition Editor");
48 window->resize(640, 400);
49 window->set_icon(app_icon.bitmap_for_size(16));
50
51 if (getuid() != 0) {
52 auto error_message = "PartitionEditor must be run as root in order to open raw block devices and read partition tables."sv;
53 GUI::MessageBox::show_error(window, error_message);
54 return Error::from_string_view(error_message);
55 }
56
57 auto widget = TRY(window->set_main_widget<GUI::Widget>());
58 TRY(widget->load_from_gml(partition_editor_window_gml));
59
60 auto device_paths = get_device_paths();
61
62 auto partition_model = PartitionEditor::PartitionModel::create();
63 TRY(partition_model->set_device_path(device_paths.first()));
64
65 auto& device_combobox = *widget->find_descendant_of_type_named<GUI::ComboBox>("device_combobox");
66 device_combobox.set_model(GUI::ItemListModel<DeprecatedString>::create(device_paths));
67 device_combobox.set_only_allow_values_from_model(true);
68 device_combobox.set_selected_index(0);
69 device_combobox.on_change = [&](auto const& path, auto const&) {
70 auto result = partition_model->set_device_path(path);
71 if (result.is_error())
72 GUI::MessageBox::show_error(window, DeprecatedString::formatted("No partition table found for device {}", path));
73 };
74
75 auto& partition_table_view = *widget->find_descendant_of_type_named<GUI::TableView>("partition_table_view");
76 partition_table_view.set_model(partition_model);
77 partition_table_view.set_focus(true);
78
79 auto& file_menu = window->add_menu("&File");
80 file_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
81 app->quit();
82 }));
83
84 auto help_menu = TRY(window->try_add_menu("&Help"));
85 TRY(help_menu->try_add_action(GUI::CommonActions::make_command_palette_action(window)));
86 TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("Partition Editor", app_icon, window)));
87
88 window->show();
89 return app->exec();
90}