Skip to content
API Documentation
BastionGuard™
RestoreDeviceBox.vala
Go to the documentation of this file.
1/*
2 * RestoreDeviceBox.vala
3 */
4
5using Gtk;
6using Gee;
7
13using TeeJee.System;
14using TeeJee.Misc;
15
16class RestoreDeviceBox : Gtk.Box{
17
18 private Gtk.Box infobar_location;
19 private Gtk.Label lbl_infobar_location;
20 private Gtk.Box option_box;
21 private Gtk.Label lbl_header_subvol;
22 private bool show_volume_name = false;
23
24 private Gtk.SizeGroup sg_mount_point = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
25 private Gtk.SizeGroup sg_device = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
26 private Gtk.SizeGroup sg_mount_options = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
27 private Gtk.Window parent_window;
28
29 public RestoreDeviceBox (Gtk.Window _parent_window) {
30 log_debug("RestoreDeviceBox: RestoreDeviceBox()");
31 GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6);
32 parent_window = _parent_window;
33 margin_top = 12;
34 margin_bottom = 12;
35 margin_start = 12;
36 margin_end = 12;
37
38 var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
39 append(hbox);
40 add_label_header(hbox, _("Select Target Device"), true);
41
42 var label = add_label(hbox, "");
43 label.hexpand = true;
44
45 Gtk.SizeGroup size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
46 var btn_refresh = add_button(hbox, _("Refresh"), "", size_group, null);
47 btn_refresh.clicked.connect(()=>{
49 refresh();
50 });
51
52 if (App.mirror_system){
53 add_label(this, _("Select the target devices where system will be cloned."));
54 }
55 else{
56 add_label(this,
57 _("Select the devices where files will be restored.") + "\n" +
58 _("Devices from which snapshot was created are pre-selected."));
59 }
60
61 hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
62 hbox.margin_top = 12;
63 append(hbox);
64
65 label = add_label(hbox, _("Path") + " ", true, true);
66 label.xalign = 0.0f;
67 sg_mount_point.add_widget(label);
68
69 label = add_label(hbox, _("Device") + " ", true, true);
70 label.xalign = 0.0f;
71 sg_device.add_widget(label);
72
73 label = add_label(hbox, _("Subvolume"), true, true);
74 label.xalign = 0.5f;
75 label.visible = false;
76 lbl_header_subvol = label;
77
78 option_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
79 append(option_box);
80
83 log_debug("RestoreDeviceBox: RestoreDeviceBox(): exit");
84 }
85
86 public void refresh(bool reset_device_selections = true){
87 log_debug("RestoreDeviceBox: refresh()");
89 create_device_selection_options(reset_device_selections);
91 log_debug("RestoreDeviceBox: refresh(): exit");
92 }
93
94 private void create_device_selection_options(bool reset_device_selections){
95 if (reset_device_selections){
97 }
98
99 show_volume_name = false;
100 foreach(var entry in App.mount_list){
101 if ((entry.device != null) && ((entry.subvolume_name().length > 0) || (entry.lvm_name().length > 0))){
102 show_volume_name = true;
103 break;
104 }
105 }
106
107 lbl_header_subvol.visible = show_volume_name;
108
109 while (option_box.get_first_child() != null){
110 option_box.remove(option_box.get_first_child());
111 }
112
113 foreach(MountEntry entry in App.mount_list){
115 }
116
117 show();
118 }
119
121 var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
122 option_box.append(box);
123
124 var label = add_label(box, entry.mount_point, true);
125 sg_mount_point.add_widget(label);
126
127 var combo = add_device_combo(box, entry);
128 sg_device.add_widget(combo);
129
130 if (show_volume_name){
131 string txt = "";
132 if (entry.subvolume_name().length > 0){
133 txt = "%s".printf(entry.subvolume_name());
134 }
135 else {
136 txt = "%s".printf(entry.lvm_name());
137 }
138 label = add_label(box, txt, false);
139 sg_mount_options.add_widget(label);
140 }
141 }
142
143 private Gtk.ComboBoxText add_device_combo(Gtk.Box box, MountEntry entry){
144 var combo = new Gtk.ComboBoxText();
145 combo.hexpand = true;
146 box.append(combo);
147
148 Gee.ArrayList<Device?> device_map = new Gee.ArrayList<Device?>();
149 var active = -1;
150 var index = -1;
151
152 if (entry.mount_point != "/"){
153 index++;
154 device_map.add(null);
155 combo.append_text(_("Keep on Root Device"));
156 }
157
158 foreach(var dev in App.partitions){
159 if ((dev.type == "loop") || (dev.fstype == "iso9660")){
160 continue;
161 }
162
163 if (dev.type != "disk"){
164 if ((entry.mount_point == "/") || (entry.mount_point == "/home")){
165 if (!dev.has_linux_filesystem()){
166 continue;
167 }
168 }
169
170 if (dev.has_children()){
171 continue;
172 }
173 }
174
175 index++;
176 device_map.add(dev);
177 combo.append_text(dev.description());
178
179 if (entry.device != null){
180 if (dev.uuid == entry.device.uuid){
181 active = index;
182 }
183 else if (dev.has_parent() && (dev.parent.uuid == entry.device.uuid)){
184 active = index;
185 }
186 else if (dev.has_children() && (dev.children[0].uuid == entry.device.uuid)){
187 active = index;
188 }
189 }
190 }
191
192 if ((active == -1) && (entry.mount_point != "/")){
193 active = 0;
194 }
195
196 combo.active = active;
197 combo.changed.connect(() => {
198 int current_index = combo.get_active();
199 if ((current_index < 0) || (current_index >= device_map.size)){
200 log_debug("device combo: active is -1");
201 return;
202 }
203
204 Device? current_dev = device_map[current_index];
205
206 if ((current_dev != null) && current_dev.is_encrypted_partition()){
207 log_debug("add_device_combo().changed: unlocking encrypted device..");
208 string msg_out, msg_err;
209 var luks_unlocked = Device.luks_unlock(
210 current_dev, "", "", parent_window, out msg_out, out msg_err);
211
212 if (luks_unlocked == null){
213 log_debug("add_device_combo().changed: failed to unlock");
214 if (entry.mount_point == "/"){
215 int fallback_index = -1;
216 for (int i = 0; i < device_map.size; i++){
217 Device? dev_iter = device_map[i];
218 if ((dev_iter != null) && (entry.device != null) && (dev_iter.device == entry.device.device)){
219 fallback_index = i;
220 break;
221 }
222 }
223 combo.active = fallback_index;
224 }
225 else{
226 combo.active = 0;
227 }
228 return;
229 }
230 else{
231 log_debug("add_device_combo().changed: unlocked");
232 if (entry.mount_point == "/"){
233 App.dst_root = luks_unlocked;
235 }
236 entry.device = luks_unlocked;
237 refresh(false);
238 return;
239 }
240 }
241
242 entry.device = current_dev;
243 if (entry.mount_point == "/"){
244 App.dst_root = current_dev;
246 }
247 });
248
249 return combo;
250 }
251
252 private void add_boot_options(){
253 var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
254 append(hbox);
255 string tt = _("[For Experienced Users] Change these settings if the restored system fails to boot.");
256 var button = add_button(hbox, _("Bootloader Options (Advanced)"), tt, null, null);
257 button.margin_start = 10;
258 button.margin_end = 10;
259 button.margin_top = 10;
260 button.margin_bottom = 10;
261
262 button.clicked.connect(()=>{
264 ((MainWindow) parent_window).show_settings();
265 }
266 else{
267 var win = new BootOptionsWindow();
268 win.set_transient_for(parent_window);
269 }
270 });
271 }
272
274 var infobar = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
275 infobar.visible = false;
276 append(infobar);
277 infobar_location = infobar;
278
279 var content = infobar;
280 var label = add_label(content, "");
281 lbl_infobar_location = label;
282 }
283
285 if (App.dst_root == App.sys_root){
286 return true;
287 }
288
289 foreach(var entry in App.mount_list){
290 if ((entry.mount_point == "/") && (entry.device == null)){
291 gtk_messagebox(_("Root device not selected"), _("Select the device for root file system (/)"), parent_window, true);
292 return false;
293 }
294 }
295
296 if (App.mirror_system){
297 foreach(var entry in App.mount_list){
298 if (entry.mount_point != "/"){ continue; }
299 bool same = false;
300 if (entry.device.uuid == App.sys_root.uuid){
301 same = true;
302 }
303 else if (entry.device.has_parent() && App.sys_root.has_parent()){
304 if (entry.device.uuid == App.sys_root.parent.uuid){
305 same = true;
306 }
307 }
308 if (same){
309 gtk_messagebox(_("Target device is same as system device"), _("Select another device for root file system (/)"), parent_window, true);
310 return false;
311 }
312 break;
313 }
314 }
315
316 foreach(var entry in App.mount_list){
317 if ((entry.mount_point == "/boot") && (entry.device == null)){
318 if ((App.dst_root != null) && (App.dst_root.is_on_encrypted_partition())){
319 gtk_messagebox(
320 _("Boot device not selected"),
321 _("An encrypted device is selected for root file system (/). The boot directory (/boot) must be mounted on a non-encrypted device for the system to boot successfully.\n\nEither select a non-encrypted device for boot directory or select a non-encrypted device for root filesystem."),
322 parent_window, true);
323 return false;
324 }
325 }
326 }
327
328 if (App.reinstall_grub2 && (App.grub_device.length == 0)){
329 gtk_messagebox(_("GRUB device not selected"), _("Please select the GRUB device"), parent_window, true);
330 return false;
331 }
332
333 bool supported = App.check_btrfs_layout(App.dst_root, App.dst_home, false);
334 if (!supported){
335 var title = _("Unsupported Subvolume Layout") + " (%s)".printf(App.dst_root.device);
336 var msg = _("Partition has an unsupported subvolume layout.") + " ";
337 msg += _("Only ubuntu-type layouts with @ and @home subvolumes are currently supported.") + "\n\n";
338 gtk_messagebox(title, msg, parent_window, true);
339 return false;
340 }
341
343 if (status == false){
344 gtk_messagebox(_("Error"), _("Failed to mount devices"), parent_window, true);
345 return false;
346 }
347
348 return true;
349 }
350}
Main App
#define _(s)
Device parent
Definition Device.vala:86
string uuid
Definition Device.vala:50
bool is_on_encrypted_partition()
Definition Device.vala:220
bool is_encrypted_partition()
Definition Device.vala:216
static ? Device luks_unlock(Device luks_device, string mapped_name, string passphrase, Gtk.Window? parent_window, out string message, out string details)
Definition Device.vala:1387
bool has_parent()
Definition Device.vala:243
string device
Definition Device.vala:44
Device sys_root
Definition Main.vala:75
Device? dst_root
Definition Main.vala:1948
bool check_btrfs_layout(Device? dev_root, Device? dev_home, bool unlock)
Definition Main.vala:507
Gee.ArrayList< Device > partitions
Definition Main.vala:59
Device? dst_home
Definition Main.vala:2005
Gee.ArrayList< MountEntry > mount_list
Definition Main.vala:67
void update_partitions()
Definition Main.vala:3819
void init_boot_options()
Definition Main.vala:2265
bool mirror_system
Definition Main.vala:85
bool reinstall_grub2
Definition Main.vala:138
bool mount_target_devices(Gtk.Window? parent_win=null)
Definition Main.vala:3910
void init_mount_list()
Definition Main.vala:2075
string grub_device
Definition Main.vala:141
string mount_point
string subvolume_name()
string lvm_name()
void add_device_selection_option(MountEntry entry)
Gtk.SizeGroup sg_mount_options
RestoreDeviceBox(Gtk.Window _parent_window)
Gtk.SizeGroup sg_mount_point
Gtk.ComboBoxText add_device_combo(Gtk.Box box, MountEntry entry)
Gtk.Label lbl_infobar_location
void refresh(bool reset_device_selections=true)
Gtk.SizeGroup sg_device
void create_device_selection_options(bool reset_device_selections)
Gtk.Label add_label(Gtk.Box box, string text, bool bold=false, bool italic=false, bool large=false)
void log_debug(string message)