sculpt: make storage target configurable

This patch lays the selection of the used storage target into the hands
of the config/manager file. By default, Sculpt selects the target by its
built-in heuristics, probing for a Sculpt partition. However, by
specifying a <target> node, one can explicitly select a storage target.

E.g., for using the 2nd partition of the SATA disk connected to port 1
of the AHCI controller, one can now specify:

  <target driver="ahci" port="1" partition="2"/>

For selecting the ram_fs as target:

  <target driver="ram_fs"/>

The latter case is particularly useful for custom Sculpt scenarios
deployed entirely from RAM. For such scenarios, add two lines to
your .sculpt file:

  ram_fs:  depot
  manager: use_ram_fs

The first line configures the ram_fs such that the depot is mounted
as a tar archive. The second line configures the sculpt manager to
select the ram_fs as storage target. You can find this feature
exemplified in default-linux.sculpt scenario.

  build/x86_64$ make run/sculpt_test KERNEL=linux BOARD=linux

It is worth noting that the configuration can be changed at runtime.
This allows for switching between different storage targets on the fly.

Issue #5166
This commit is contained in:
Norman Feske 2024-03-28 12:34:57 +01:00 committed by Christian Helmuth
parent 508e0bdfbf
commit 4a1a29b3d0
9 changed files with 133 additions and 73 deletions

View File

@ -2,6 +2,7 @@
drivers: linux drivers: linux
deploy: example deploy: example
ram_fs: depot ram_fs: depot
manager: use_ram_fs
# selection of launcher-menu entries # selection of launcher-menu entries
launcher: sticks_blue_backdrop nano3d system_shell launcher: sticks_blue_backdrop nano3d system_shell

View File

@ -0,0 +1,3 @@
<config>
<target driver="ram_fs"/>
</config>

View File

@ -255,6 +255,8 @@ struct Sculpt::Main : Input_event_handler,
void _handle_config(Xml_node const &config) void _handle_config(Xml_node const &config)
{ {
_handle_storage_devices();
_verbose_modem = config.attribute_value("verbose_modem", false); _verbose_modem = config.attribute_value("verbose_modem", false);
} }
@ -303,20 +305,22 @@ struct Sculpt::Main : Input_event_handler,
void _handle_storage_devices() void _handle_storage_devices()
{ {
Storage_target const orig_sculpt_partition = _storage._sculpt_partition; Storage_target const orig_target = _storage._selected_target;
bool total_progress = false; bool total_progress = false;
for (bool progress = true; progress; total_progress |= progress) { for (bool progress = true; progress; total_progress |= progress) {
progress = false; progress = false;
_drivers.with_storage_devices([&] (Drivers::Storage_devices const &devices) { _drivers.with_storage_devices([&] (Drivers::Storage_devices const &devices) {
progress = _storage.update(devices.usb, devices.ahci, _config.with_xml([&] (Xml_node const &config) {
devices.nvme, devices.mmc).progress; }); progress = _storage.update(config,
devices.usb, devices.ahci,
devices.nvme, devices.mmc).progress; }); });
/* update USB policies for storage devices */ /* update USB policies for storage devices */
_drivers.update_usb(); _drivers.update_usb();
} }
if (orig_sculpt_partition != _storage._sculpt_partition) if (orig_target != _storage._selected_target)
_restart_from_storage_target(); _restart_from_storage_target();
if (total_progress) { if (total_progress) {
@ -410,7 +414,7 @@ struct Sculpt::Main : Input_event_handler,
*/ */
bool _update_running() const bool _update_running() const
{ {
return _storage._sculpt_partition.valid() return _storage._selected_target.valid()
&& !_prepare_in_progress() && !_prepare_in_progress()
&& _network.ready() && _network.ready()
&& _deploy.update_needed(); && _deploy.update_needed();
@ -750,7 +754,7 @@ struct Sculpt::Main : Input_event_handler,
Conditional_widget<Storage_widget> _storage_widget { Conditional_widget<Storage_widget> _storage_widget {
Conditional_widget<Storage_widget>::Attr { .centered = true }, Conditional_widget<Storage_widget>::Attr { .centered = true },
Id { "storage dialog" }, _storage._storage_devices, _storage._sculpt_partition }; Id { "storage dialog" }, _storage._storage_devices, _storage._selected_target };
/* /*
* Network section * Network section
@ -797,7 +801,7 @@ struct Sculpt::Main : Input_event_handler,
Conditional_widget<Graph> Conditional_widget<Graph>
_graph { Id { "graph" }, _graph { Id { "graph" },
_runtime_state, _cached_runtime_config, _storage._storage_devices, _runtime_state, _cached_runtime_config, _storage._storage_devices,
_storage._sculpt_partition, _storage._ram_fs_state, _storage._selected_target, _storage._ram_fs_state,
_popup.state, _deploy._children }; _popup.state, _deploy._children };
Conditional_widget<Network_widget> Conditional_widget<Network_widget>
@ -897,28 +901,28 @@ struct Sculpt::Main : Input_event_handler,
_software_title_bar.view_status(s, _software_status_message()); }); _software_title_bar.view_status(s, _software_status_message()); });
s.widget(_software_tabs_widget, _software_title_bar.selected(), s.widget(_software_tabs_widget, _software_title_bar.selected(),
_storage._sculpt_partition, _presets, _software_status_available()); _storage._selected_target, _presets, _software_status_available());
s.widget(_graph, _software_title_bar.selected() s.widget(_graph, _software_title_bar.selected()
&& _software_tabs_widget.hosted.runtime_selected()); && _software_tabs_widget.hosted.runtime_selected());
s.widget(_software_presets_widget, _software_title_bar.selected() s.widget(_software_presets_widget, _software_title_bar.selected()
&& _software_tabs_widget.hosted.presets_selected() && _software_tabs_widget.hosted.presets_selected()
&& _storage._sculpt_partition.valid(), && _storage._selected_target.valid(),
_presets); _presets);
s.widget(_software_options_widget, _software_title_bar.selected() s.widget(_software_options_widget, _software_title_bar.selected()
&& _software_tabs_widget.hosted.options_selected() && _software_tabs_widget.hosted.options_selected()
&& _storage._sculpt_partition.valid()); && _storage._selected_target.valid());
s.widget(_software_add_widget, _software_title_bar.selected() s.widget(_software_add_widget, _software_title_bar.selected()
&& _software_tabs_widget.hosted.add_selected() && _software_tabs_widget.hosted.add_selected()
&& _storage._sculpt_partition.valid()); && _storage._selected_target.valid());
_image_index_rom.with_xml([&] (Xml_node const &image_index) { _image_index_rom.with_xml([&] (Xml_node const &image_index) {
s.widget(_software_update_widget, _software_title_bar.selected() s.widget(_software_update_widget, _software_title_bar.selected()
&& _software_tabs_widget.hosted.update_selected() && _software_tabs_widget.hosted.update_selected()
&& _storage._sculpt_partition.valid(), && _storage._selected_target.valid(),
image_index); image_index);
}); });
@ -966,7 +970,7 @@ struct Sculpt::Main : Input_event_handler,
void _handle_runtime_state(Xml_node const &); void _handle_runtime_state(Xml_node const &);
Runtime_state _runtime_state { _heap, _storage._sculpt_partition }; Runtime_state _runtime_state { _heap, _storage._selected_target };
Managed_config<Main> _runtime_config { Managed_config<Main> _runtime_config {
_env, "config", "runtime", *this, &Main::_handle_runtime }; _env, "config", "runtime", *this, &Main::_handle_runtime };
@ -1314,9 +1318,15 @@ struct Sculpt::Main : Input_event_handler,
void use(Storage_target const &target) override void use(Storage_target const &target) override
{ {
_storage._sculpt_partition = target; Storage_target const orig_target = _storage._selected_target;
_storage._selected_target = target;
_software_update_widget.hosted.reset(); _software_update_widget.hosted.reset();
_download_queue.reset(); _download_queue.reset();
if (orig_target != _storage._selected_target)
_restart_from_storage_target();
generate_runtime_config(); generate_runtime_config();
} }
@ -2382,7 +2392,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
/* /*
* Load configuration and update depot config on the sculpt partition * Load configuration and update depot config on the sculpt partition
*/ */
if (_storage._sculpt_partition.valid() && _prepare_in_progress()) if (_storage._selected_target.valid() && _prepare_in_progress())
xml.node("start", [&] { xml.node("start", [&] {
gen_prepare_start_content(xml, _prepare_version); }); gen_prepare_start_content(xml, _prepare_version); });
@ -2390,7 +2400,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
* Spawn chroot instances for accessing '/depot' and '/public'. The * Spawn chroot instances for accessing '/depot' and '/public'. The
* chroot instances implicitly refer to the 'default_fs_rw'. * chroot instances implicitly refer to the 'default_fs_rw'.
*/ */
if (_storage._sculpt_partition.valid()) { if (_storage._selected_target.valid()) {
auto chroot = [&] (Start_name const &name, Path const &path, Writeable w) { auto chroot = [&] (Start_name const &name, Path const &path, Writeable w) {
xml.node("start", [&] { xml.node("start", [&] {
@ -2405,7 +2415,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
} }
/* execute file operations */ /* execute file operations */
if (_storage._sculpt_partition.valid()) if (_storage._selected_target.valid())
if (_file_operation_queue.any_operation_in_progress()) if (_file_operation_queue.any_operation_in_progress())
xml.node("start", [&] { xml.node("start", [&] {
gen_fs_tool_start_content(xml, _fs_tool_version, gen_fs_tool_start_content(xml, _fs_tool_version,
@ -2417,7 +2427,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
xml.node("start", [&] { xml.node("start", [&] {
gen_update_start_content(xml); }); gen_update_start_content(xml); });
if (_storage._sculpt_partition.valid() && !_prepare_in_progress()) { if (_storage._selected_target.valid() && !_prepare_in_progress()) {
xml.node("start", [&] { xml.node("start", [&] {
gen_launcher_query_start_content(xml); }); gen_launcher_query_start_content(xml); });

View File

@ -98,7 +98,7 @@ void Graph::_view_selected_node_content(Scope<Depgraph, Frame, Vbox> &s,
} }
if (name == "ram_fs") if (name == "ram_fs")
s.widget(_ram_fs_widget, _sculpt_partition, _ram_fs_state); s.widget(_ram_fs_widget, _selected_target, _ram_fs_state);
String<100> const String<100> const
ram (Capacity{info.assigned_ram - info.avail_ram}, " / ", ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
@ -130,7 +130,7 @@ void Graph::_view_selected_node_content(Scope<Depgraph, Frame, Vbox> &s,
void Graph::view(Scope<Depgraph> &s) const void Graph::view(Scope<Depgraph> &s) const
{ {
if (Feature::PRESENT_PLUS_MENU && _sculpt_partition.valid()) if (Feature::PRESENT_PLUS_MENU && _selected_target.valid())
s.widget(_plus, _popup_state == Popup::VISIBLE); s.widget(_plus, _popup_state == Popup::VISIBLE);
/* parent roles */ /* parent roles */
@ -185,7 +185,7 @@ void Graph::view(Scope<Depgraph> &s) const
Dialog::Id primary_dep = Id { component.primary_dependency }; Dialog::Id primary_dep = Id { component.primary_dependency };
if (primary_dep.value == "default_fs_rw") if (primary_dep.value == "default_fs_rw")
primary_dep = Dialog::Id { _sculpt_partition.fs() }; primary_dep = Dialog::Id { _selected_target.fs() };
/* primary dependency is another component */ /* primary dependency is another component */
_runtime_config.with_graph_id(primary_dep, _runtime_config.with_graph_id(primary_dep,
@ -222,7 +222,7 @@ void Graph::view(Scope<Depgraph> &s) const
return; return;
if (dep_name == "default_fs_rw") if (dep_name == "default_fs_rw")
dep_name = _sculpt_partition.fs(); dep_name = _selected_target.fs();
Dialog::Id dep_id { dep_name }; Dialog::Id dep_id { dep_name };
@ -264,7 +264,7 @@ void Graph::click(Clicked_at const &at, Action &action)
action.open_popup_dialog(popup_anchor(at._location)); action.open_popup_dialog(popup_anchor(at._location));
}); });
_ram_fs_widget .propagate(at, _sculpt_partition, action); _ram_fs_widget .propagate(at, _selected_target, action);
_ahci_devices_widget.propagate(at, action); _ahci_devices_widget.propagate(at, action);
_nvme_devices_widget.propagate(at, action); _nvme_devices_widget.propagate(at, action);
_mmc_devices_widget .propagate(at, action); _mmc_devices_widget .propagate(at, action);

View File

@ -40,7 +40,7 @@ struct Sculpt::Graph : Widget<Depgraph>
Runtime_state &_runtime_state; Runtime_state &_runtime_state;
Runtime_config const &_runtime_config; Runtime_config const &_runtime_config;
Storage_devices const &_storage_devices; Storage_devices const &_storage_devices;
Storage_target const &_sculpt_partition; Storage_target const &_selected_target;
Ram_fs_state const &_ram_fs_state; Ram_fs_state const &_ram_fs_state;
Popup::State const &_popup_state; Popup::State const &_popup_state;
Depot_deploy::Children const &_deploy_children; Depot_deploy::Children const &_deploy_children;
@ -56,19 +56,19 @@ struct Sculpt::Graph : Widget<Depgraph>
Hosted<Depgraph, Frame, Vbox, Frame, Ahci_devices_widget> Hosted<Depgraph, Frame, Vbox, Frame, Ahci_devices_widget>
_ahci_devices_widget { Id { "ahci_devices" }, _ahci_devices_widget { Id { "ahci_devices" },
_storage_devices, _sculpt_partition }; _storage_devices, _selected_target };
Hosted<Depgraph, Frame, Vbox, Frame, Nvme_devices_widget> Hosted<Depgraph, Frame, Vbox, Frame, Nvme_devices_widget>
_nvme_devices_widget { Id { "nvme_devices" }, _nvme_devices_widget { Id { "nvme_devices" },
_storage_devices, _sculpt_partition }; _storage_devices, _selected_target };
Hosted<Depgraph, Frame, Vbox, Frame, Mmc_devices_widget> Hosted<Depgraph, Frame, Vbox, Frame, Mmc_devices_widget>
_mmc_devices_widget { Id { "mmc_devices" }, _mmc_devices_widget { Id { "mmc_devices" },
_storage_devices, _sculpt_partition }; _storage_devices, _selected_target };
Hosted<Depgraph, Frame, Vbox, Frame, Usb_devices_widget> Hosted<Depgraph, Frame, Vbox, Frame, Usb_devices_widget>
_usb_devices_widget { Id { "usb_devices" }, _usb_devices_widget { Id { "usb_devices" },
_storage_devices, _sculpt_partition }; _storage_devices, _selected_target };
bool _storage_selected = false; bool _storage_selected = false;
@ -79,13 +79,13 @@ struct Sculpt::Graph : Widget<Depgraph>
Graph(Runtime_state &runtime_state, Graph(Runtime_state &runtime_state,
Runtime_config const &runtime_config, Runtime_config const &runtime_config,
Storage_devices const &storage_devices, Storage_devices const &storage_devices,
Storage_target const &sculpt_partition, Storage_target const &selected_target,
Ram_fs_state const &ram_fs_state, Ram_fs_state const &ram_fs_state,
Popup::State const &popup_state, Popup::State const &popup_state,
Depot_deploy::Children const &deploy_children) Depot_deploy::Children const &deploy_children)
: :
_runtime_state(runtime_state), _runtime_config(runtime_config), _runtime_state(runtime_state), _runtime_config(runtime_config),
_storage_devices(storage_devices), _sculpt_partition(sculpt_partition), _storage_devices(storage_devices), _selected_target(selected_target),
_ram_fs_state(ram_fs_state), _popup_state(popup_state), _ram_fs_state(ram_fs_state), _popup_state(popup_state),
_deploy_children(deploy_children) _deploy_children(deploy_children)
{ } { }

View File

@ -119,6 +119,13 @@ struct Sculpt::Main : Input_event_handler,
void _handle_gui_mode(); void _handle_gui_mode();
Rom_handler<Main> _config { _env, "config", *this, &Main::_handle_config };
void _handle_config(Xml_node const &)
{
_handle_storage_devices();
}
Screensaver _screensaver { _env, *this }; Screensaver _screensaver { _env, *this };
/** /**
@ -249,20 +256,22 @@ struct Sculpt::Main : Input_event_handler,
void _handle_storage_devices() void _handle_storage_devices()
{ {
Storage_target const orig_sculpt_partition = _storage._sculpt_partition; Storage_target const orig_target = _storage._selected_target;
bool total_progress = false; bool total_progress = false;
for (bool progress = true; progress; total_progress |= progress) { for (bool progress = true; progress; total_progress |= progress) {
progress = false; progress = false;
_drivers.with_storage_devices([&] (Drivers::Storage_devices const &devices) { _drivers.with_storage_devices([&] (Drivers::Storage_devices const &devices) {
progress = _storage.update(devices.usb, devices.ahci, _config.with_xml([&] (Xml_node const &config) {
devices.nvme, devices.mmc).progress; }); progress = _storage.update(config,
devices.usb, devices.ahci,
devices.nvme, devices.mmc).progress; }); });
/* update USB policies for storage devices */ /* update USB policies for storage devices */
_drivers.update_usb(); _drivers.update_usb();
} }
if (orig_sculpt_partition != _storage._sculpt_partition) if (orig_target != _storage._selected_target)
_restart_from_storage_target(); _restart_from_storage_target();
if (total_progress) { if (total_progress) {
@ -381,7 +390,7 @@ struct Sculpt::Main : Input_event_handler,
*/ */
bool _update_running() const bool _update_running() const
{ {
return _storage._sculpt_partition.valid() return _storage._selected_target.valid()
&& !_prepare_in_progress() && !_prepare_in_progress()
&& _network.ready() && _network.ready()
&& _deploy.update_needed(); && _deploy.update_needed();
@ -603,7 +612,7 @@ struct Sculpt::Main : Input_event_handler,
bool system_available() const override bool system_available() const override
{ {
return _storage._sculpt_partition.valid() && !_prepare_in_progress(); return _storage._selected_target.valid() && !_prepare_in_progress();
} }
struct Diag_dialog : Top_level_dialog struct Diag_dialog : Top_level_dialog
@ -669,7 +678,7 @@ struct Sculpt::Main : Input_event_handler,
void _handle_runtime_state(Xml_node const &); void _handle_runtime_state(Xml_node const &);
Runtime_state _runtime_state { _heap, _storage._sculpt_partition }; Runtime_state _runtime_state { _heap, _storage._selected_target };
Managed_config<Main> _runtime_config { Managed_config<Main> _runtime_config {
_env, "config", "runtime", *this, &Main::_handle_runtime }; _env, "config", "runtime", *this, &Main::_handle_runtime };
@ -801,10 +810,15 @@ struct Sculpt::Main : Input_event_handler,
void use(Storage_target const &target) override void use(Storage_target const &target) override
{ {
_storage._sculpt_partition = target; Storage_target const orig_target = _storage._selected_target;
_storage._selected_target = target;
_system_dialog.reset_update_widget(); _system_dialog.reset_update_widget();
_download_queue.reset(); _download_queue.reset();
if (orig_target != _storage._selected_target)
_restart_from_storage_target();
/* hide system panel button and system dialog when "un-using" */ /* hide system panel button and system dialog when "un-using" */
_panel_dialog.refresh(); _panel_dialog.refresh();
_system_dialog.refresh(); _system_dialog.refresh();
@ -1394,7 +1408,7 @@ struct Sculpt::Main : Input_event_handler,
Popup _popup { }; Popup _popup { };
Graph _graph { _runtime_state, _cached_runtime_config, _storage._storage_devices, Graph _graph { _runtime_state, _cached_runtime_config, _storage._storage_devices,
_storage._sculpt_partition, _storage._ram_fs_state, _storage._selected_target, _storage._ram_fs_state,
_popup.state, _deploy._children }; _popup.state, _deploy._children };
struct Graph_dialog : Dialog::Top_level_dialog struct Graph_dialog : Dialog::Top_level_dialog
@ -2049,7 +2063,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
/* /*
* Load configuration and update depot config on the sculpt partition * Load configuration and update depot config on the sculpt partition
*/ */
if (_storage._sculpt_partition.valid() && _prepare_in_progress()) if (_storage._selected_target.valid() && _prepare_in_progress())
xml.node("start", [&] { xml.node("start", [&] {
gen_prepare_start_content(xml, _prepare_version); }); gen_prepare_start_content(xml, _prepare_version); });
@ -2061,7 +2075,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
* Spawn chroot instances for accessing '/depot' and '/public'. The * Spawn chroot instances for accessing '/depot' and '/public'. The
* chroot instances implicitly refer to the 'default_fs_rw'. * chroot instances implicitly refer to the 'default_fs_rw'.
*/ */
if (_storage._sculpt_partition.valid()) { if (_storage._selected_target.valid()) {
auto chroot = [&] (Start_name const &name, Path const &path, Writeable w) { auto chroot = [&] (Start_name const &name, Path const &path, Writeable w) {
xml.node("start", [&] { xml.node("start", [&] {
@ -2076,7 +2090,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
} }
/* execute file operations */ /* execute file operations */
if (_storage._sculpt_partition.valid()) if (_storage._selected_target.valid())
if (_file_operation_queue.any_operation_in_progress()) if (_file_operation_queue.any_operation_in_progress())
xml.node("start", [&] { xml.node("start", [&] {
gen_fs_tool_start_content(xml, _fs_tool_version, gen_fs_tool_start_content(xml, _fs_tool_version,
@ -2088,7 +2102,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
xml.node("start", [&] { xml.node("start", [&] {
gen_update_start_content(xml); }); gen_update_start_content(xml); });
if (_storage._sculpt_partition.valid() && !_prepare_in_progress()) { if (_storage._selected_target.valid() && !_prepare_in_progress()) {
xml.node("start", [&] { xml.node("start", [&] {
gen_launcher_query_start_content(xml); }); gen_launcher_query_start_content(xml); });

View File

@ -28,6 +28,15 @@ struct Sculpt::Storage_target
Storage_device::Port port; Storage_device::Port port;
Partition::Number partition; Partition::Number partition;
static Storage_target from_xml(Xml_node const &target)
{
return {
.driver = target.attribute_value("driver", Storage_device::Driver()),
.port = target.attribute_value("port", Storage_device::Port()),
.partition = target.attribute_value("partition", Partition::Number())
};
}
bool operator == (Storage_target const &other) const bool operator == (Storage_target const &other) const
{ {
return (driver == other.driver) return (driver == other.driver)

View File

@ -17,7 +17,8 @@
using namespace Sculpt; using namespace Sculpt;
Progress Storage::update(Xml_node const &usb, Xml_node const &ahci, Progress Storage::update(Xml_node const &config,
Xml_node const &usb, Xml_node const &ahci,
Xml_node const &nvme, Xml_node const &mmc) Xml_node const &nvme, Xml_node const &mmc)
{ {
bool progress = false; bool progress = false;
@ -36,49 +37,67 @@ Progress Storage::update(Xml_node const &usb, Xml_node const &ahci,
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device &dev) { _storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device &dev) {
dev.process_report(); }); dev.process_report(); });
if (!_sculpt_partition.valid()) { Storage_target const orig_selected_target = _selected_target;
Storage_target const orig_configured_target = _configured_target;
config.with_sub_node("target",
[&] (Xml_node const &target) {
Storage_target const configured_target = Storage_target::from_xml(target);
if (configured_target != _configured_target) {
_configured_target = configured_target;
_malconfiguration = false; } },
[&] { _configured_target = { }; });
if (orig_configured_target != _configured_target)
_selected_target = { };
if (!_selected_target.valid()) {
bool const all_devices_enumerated = !usb .has_type("empty") bool const all_devices_enumerated = !usb .has_type("empty")
&& !ahci.has_type("empty") && !ahci.has_type("empty")
&& !nvme.has_type("empty") && !nvme.has_type("empty")
&& !mmc .has_type("empty"); && !mmc .has_type("empty");
if (all_devices_enumerated) { if (all_devices_enumerated) {
if (_configured_target.valid())
Storage_target const default_target = _selected_target = _malconfiguration ? Storage_target { } : _configured_target;
_discovery_state.detect_default_target(_storage_devices); else
_selected_target = _discovery_state.detect_default_target(_storage_devices);
if (default_target.valid()) {
_sculpt_partition = default_target;
progress |= true;
}
} }
} }
/* /*
* Detect the removal of a USB stick that is currently in "use". Reset * Detect the removal of a USB stick that is currently in "use". Reset
* the '_sculpt_partition' to enable the selection of another storage * the '_selected_target' to enable the selection of another storage
* target to use. * target to use.
*/ */
else if (_sculpt_partition.valid()) { else if (_selected_target.valid()) {
bool sculpt_partition_exists = false; bool selected_target_exists = false;
if (_sculpt_partition.ram_fs()) if (_selected_target.ram_fs())
sculpt_partition_exists = true; selected_target_exists = true;
_storage_devices.for_each([&] (Storage_device const &device) { _storage_devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) { device.for_each_partition([&] (Partition const &partition) {
if (device.driver == _sculpt_partition.driver if (device.driver == _selected_target.driver
&& partition.number == _sculpt_partition.partition) && partition.number == _selected_target.partition)
sculpt_partition_exists = true; }); }); selected_target_exists = true; }); });
if (!sculpt_partition_exists) { if (!selected_target_exists) {
warning("sculpt partition unexpectedly vanished"); if (_configured_target.valid()) {
_sculpt_partition = Storage_target { }; warning("configured storage target does not exist");
progress |= true; _malconfiguration = true;
} else {
warning("selected storage target unexpectedly vanished");
}
_selected_target = { };
} }
} }
progress |= (orig_selected_target != _selected_target);
return { progress }; return { progress };
} }
@ -90,11 +109,11 @@ void Storage::gen_runtime_start_nodes(Xml_generator &xml) const
auto contains_used_fs = [&] (Storage_device const &device) auto contains_used_fs = [&] (Storage_device const &device)
{ {
if (!_sculpt_partition.valid()) if (!_selected_target.valid())
return false; return false;
return (device.port == _sculpt_partition.port) return (device.port == _selected_target.port)
&& (device.driver == _sculpt_partition.driver); && (device.driver == _selected_target.driver);
}; };
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &device) { _storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &device) {
@ -135,7 +154,7 @@ void Storage::gen_runtime_start_nodes(Xml_generator &xml) const
gen_resize2fs_start_content(xml, target); }); } gen_resize2fs_start_content(xml, target); }); }
if (partition.file_system.type != File_system::UNKNOWN) { if (partition.file_system.type != File_system::UNKNOWN) {
if (partition.file_system.inspected || target == _sculpt_partition) if (partition.file_system.inspected || target == _selected_target)
xml.node("start", [&] { xml.node("start", [&] {
gen_fs_start_content(xml, target, partition.file_system.type); }); gen_fs_start_content(xml, target, partition.file_system.type); });
@ -144,7 +163,7 @@ void Storage::gen_runtime_start_nodes(Xml_generator &xml) const
* to as "default_fs_rw" without the need to know the name of the * to as "default_fs_rw" without the need to know the name of the
* underlying storage target. * underlying storage target.
*/ */
if (target == _sculpt_partition) if (target == _selected_target)
gen_named_node(xml, "alias", "default_fs_rw", [&] { gen_named_node(xml, "alias", "default_fs_rw", [&] {
xml.attribute("child", target.fs()); }); xml.attribute("child", target.fs()); });
} }
@ -163,7 +182,7 @@ void Storage::gen_runtime_start_nodes(Xml_generator &xml) const
}); /* for each device */ }); /* for each device */
if (_sculpt_partition.ram_fs()) if (_selected_target.ram_fs())
gen_named_node(xml, "alias", "default_fs_rw", [&] { gen_named_node(xml, "alias", "default_fs_rw", [&] {
xml.attribute("child", "ram_fs"); }); xml.attribute("child", "ram_fs"); });
} }

View File

@ -31,13 +31,17 @@ struct Sculpt::Storage : Noncopyable
Ram_fs_state _ram_fs_state; Ram_fs_state _ram_fs_state;
Storage_target _sculpt_partition { }; Storage_target _configured_target { },
_selected_target { };
bool _malconfiguration = false;
Discovery_state _discovery_state { }; Discovery_state _discovery_state { };
Inspect_view_version _inspect_view_version { 0 }; Inspect_view_version _inspect_view_version { 0 };
Progress update(Xml_node const &usb_devices, Xml_node const &ahci_ports, Progress update(Xml_node const &config,
Xml_node const &usb_devices, Xml_node const &ahci_ports,
Xml_node const &nvme_namespaces, Xml_node const &mmc_devices); Xml_node const &nvme_namespaces, Xml_node const &mmc_devices);
/* /*