Updated code for reading options from command line; Auto-select default mounts while restoring from GUI; Display a confirmation prompt for device mounts before restore

This commit is contained in:
Tony George 2014-11-24 21:45:00 +05:30
parent 1f5181a63b
commit ef778674de
5 changed files with 555 additions and 244 deletions

View File

@ -877,7 +877,7 @@ public class Main : GLib.Object{
}
}
public Device read_stdin_device(Gee.ArrayList<Device> device_list){
public Device? read_stdin_device(Gee.ArrayList<Device> device_list){
string? line = stdin.read_line();
line = (line != null) ? line.strip() : line;
@ -892,44 +892,14 @@ public class Main : GLib.Object{
log_error("Invalid input");
}
else if (line.contains("/")){
bool found = false;
foreach(Device pi in device_list) {
if (!pi.has_linux_filesystem()) { continue; }
if (pi.device == line){
selected_device = pi;
found = true;
break;
}
else {
foreach(string symlink in pi.symlinks){
if (symlink == line){
selected_device = pi;
found = true;
break;
}
}
if (found){ break; }
}
}
if (!found){
selected_device = get_device_from_name(device_list, line);
if (selected_device == null){
log_error("Invalid input");
}
}
else{
int64 index;
bool found = false;
if (int64.try_parse(line, out index)){
int i = -1;
foreach(Device pi in device_list) {
if ((pi.devtype == "partition") && !pi.has_linux_filesystem()) { continue; }
if (++i == index){
selected_device = pi;
found = true;
break;
}
}
}
if (!found){
selected_device = get_device_from_index(device_list, line);
if (selected_device == null){
log_error("Invalid input");
}
}
@ -937,6 +907,78 @@ public class Main : GLib.Object{
return selected_device;
}
public Device? read_stdin_device_mounts(Gee.ArrayList<Device> device_list, MountEntry mnt){
string? line = stdin.read_line();
line = (line != null) ? line.strip() : line;
Device selected_device = null;
if ((line == null)||(line.length == 0)||(line.down() == "c")||(line.down() == "d")){
//set default
if (mirror_system){
return restore_target; //root device
}
else{
return mnt.device; //keep current
}
}
else if (line.down() == "a"){
log_msg("Aborted.");
exit_app();
exit(0);
}
else if ((line.down() == "n")||(line.down() == "r")){
return restore_target; //root device
}
else if (line.contains("/")){
selected_device = get_device_from_name(device_list, line);
if (selected_device == null){
log_error("Invalid input");
}
}
else{
selected_device = get_device_from_index(device_list, line);
if (selected_device == null){
log_error("Invalid input");
}
}
return selected_device;
}
public Device? get_device_from_index(Gee.ArrayList<Device> device_list, string index_string){
int64 index;
if (int64.try_parse(index_string, out index)){
int i = -1;
foreach(Device pi in device_list) {
if ((pi.devtype == "partition") && !pi.has_linux_filesystem()) { continue; }
if (++i == index){
return pi;
}
}
}
return null;
}
public Device? get_device_from_name(Gee.ArrayList<Device> device_list, string device_name){
foreach(Device pi in device_list) {
if (!pi.has_linux_filesystem()) { continue; }
if (pi.device == device_name){
return pi;
}
else {
foreach(string symlink in pi.symlinks){
if (symlink == device_name){
return pi;
}
}
}
}
return null;
}
public TimeShiftBackup read_stdin_snapshot(){
string? line = stdin.read_line();
line = (line != null) ? line.strip() : line;
@ -994,16 +1036,16 @@ public class Main : GLib.Object{
string? line = stdin.read_line();
line = (line != null) ? line.strip() : line;
if (line.down() == "a"){
if ((line == null)||(line.length == 0)){
log_error("Invalid input");
return false;
}
else if (line.down() == "a"){
log_msg("Aborted.");
exit_app();
exit(0);
return true;
}
else if ((line == null)||(line.length == 0)){
log_error("Invalid input");
return false;
}
else if (line.down() == "y"){
cmd_skip_grub = false;
reinstall_grub2 = true;
@ -1024,6 +1066,30 @@ public class Main : GLib.Object{
}
}
public bool read_stdin_change_device(){
string? line = stdin.read_line();
line = (line != null) ? line.strip() : line;
if ((line == null)||(line.length == 0)){
return false; //default=n
}
else if (line.down() == "a"){
log_msg("Aborted.");
exit_app();
exit(0);
return true;
}
else if (line.down() == "y"){
return true;
}
else if (line.down() == "n"){
return false;
}
else{
return false;
}
}
public bool read_stdin_restore_confirm(){
string? line = stdin.read_line();
line = (line != null) ? line.strip() : line;
@ -1992,7 +2058,7 @@ public class Main : GLib.Object{
//prompt user for target device
if (restore_target == null){
log_msg("");
log_msg(TERM_COLOR_YELLOW + _("Select target device") + ":\n" + TERM_COLOR_RESET);
log_msg(TERM_COLOR_YELLOW + _("Select target device") + " (/):\n" + TERM_COLOR_RESET);
list_devices();
log_msg("");
@ -2017,13 +2083,71 @@ public class Main : GLib.Object{
log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET);
log_msg(_("Target Device") + ": %s".printf(restore_target.device + ((symlink.length > 0) ? "" + symlink : "")), true);
log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET);
}
else{
//print error
log_error(_("Target device not specified!"));
return false;
}
//select other devices in mount_list --------------------
if (app_mode != ""){ //command line mode
init_mount_list();
for(int i = mount_list.size - 1; i >= 0; i--){
MountEntry mnt = mount_list[i];
Device dev = null;
string default_device = "";
if (mnt.mount_point == "/"){ continue; }
if (mirror_system){
default_device = restore_target.device;
}
else{
default_device = mnt.device.device;
}
//prompt user for device
if (dev == null){
log_msg("");
log_msg(TERM_COLOR_YELLOW + _("Select '%s' device (default = %s)").printf(mnt.mount_point, default_device) + ":\n" + TERM_COLOR_RESET);
list_devices();
log_msg("");
while (dev == null){
stdout.printf(TERM_COLOR_YELLOW + _("[a = Abort, d = Default (%s), r = Root device]").printf(default_device) + "\n\n" + TERM_COLOR_RESET);
stdout.printf(TERM_COLOR_YELLOW + _("Enter device name or number") + ": " + TERM_COLOR_RESET);
stdout.flush();
dev = read_stdin_device_mounts(partition_list, mnt);
}
log_msg("");
}
if (dev != null){
mnt.device = dev;
if (dev.device == restore_target.device){
mount_list.remove_at(i);
}
log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET);
if (dev.device == restore_target.device){
log_msg(_("'%s' will be on root device").printf(mnt.mount_point), true);
}
else{
log_msg(_("'%s' will be on '%s'").printf(mnt.mount_point, mnt.device.device), true);
}
log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET);
}
}
}
//mount selected devices ---------------------------------------
if (restore_target != null){
if (app_mode != ""){ //commandline mode
//init mount list
mount_list.clear();
mount_list.add(new MountEntry(restore_target,"/"));
//mount target device
//mount target device and other devices
bool status = mount_target_device(null);
if (status == false){
return false;
@ -2151,6 +2275,60 @@ public class Main : GLib.Object{
return thr_success;
}
public void init_mount_list(){
mount_list.clear();
Gee.ArrayList<FsTabEntry> fstab_list = null;
if (mirror_system){
string fstab_path = "/etc/fstab";
fstab_list = FsTabEntry.read_fstab_file(fstab_path);
}
else{
string fstab_path = snapshot_to_restore.path + "/localhost/etc/fstab";
fstab_list = FsTabEntry.read_fstab_file(fstab_path);
}
foreach(FsTabEntry mnt in fstab_list){
switch(mnt.mount_point){
case "/":
case "/boot":
case "/home":
Device mnt_dev = null;
if (mnt.device.down().has_prefix("uuid=")){
string uuid = mnt.device.down()["uuid=".length:mnt.device.length];
if (partition_map.has_key(uuid)){
mnt_dev = partition_map[uuid];
}
}
else{
foreach(Device dev in partition_list){
if (dev.device == mnt.device){
mnt_dev = dev;
break;
}
else{
foreach(string symlink in dev.symlinks){
if (symlink == mnt.device){
mnt_dev = dev;
break;
}
}
if (mnt_dev != null) { break; }
}
}
}
if (mnt_dev != null){
mount_list.add(new MountEntry(mnt_dev, mnt.mount_point));
}
break;
}
}
/*foreach(MountEntry mnt in mount_list){
log_msg("Entry:%s -> %s".printf(mnt.device.device,mnt.mount_point));
}*/
}
public string unlock_encrypted_device(Device dev, Gtk.Window? parent_win){
string mapped_name = "%s_unlocked".printf(dev.name);
string[] name_list = { "%s_unlocked".printf(dev.name), "%s_crypt".printf(dev.name), "luks-%s".printf(dev.uuid)};

View File

@ -154,11 +154,15 @@ public class RestoreWindow : Gtk.Dialog{
radio_sys.toggled.connect(() => {
sw_partitions.sensitive = radio_other.active;
refresh_tv_partitions();
if (radio_sys.active){
App.restore_target = App.root_device;
}
refresh_tv_partitions();
else{
init_mounts();
}
//tv_partitions_select_target();
cmb_boot_device_select_default();
});
@ -595,6 +599,46 @@ public class RestoreWindow : Gtk.Dialog{
});
set_app_page_state();
init_mounts();
}
private void init_mounts(){
TreeIter iter;
ListStore store;
App.init_mount_list();
if (App.mirror_system){
//default all mount points to root device except /boot
for(int i = App.mount_list.size - 1; i >= 0; i--){
MountEntry mnt = App.mount_list[i];
if (mnt.mount_point != "/boot"){
App.mount_list.remove_at(i);
}
}
/* Note:
* While cloning the system, /boot is the only mount point that we will leave unchanged (to avoid encrypted systems from breaking)
* All other mounts like /home will be defaulted to target device (to prevent the "cloned" system from using the original device)
* */
}
//find the root mount point set by user
store = (ListStore) tv_partitions.model;
for (bool next = store.get_iter_first (out iter); next; next = store.iter_next (ref iter)) {
Device pi;
string mount_point;
store.get(iter, 0, out pi);
store.get(iter, 1, out mount_point);
foreach(MountEntry mnt in App.mount_list){
if (mnt.device.device == pi.device){
store.set(iter, 1, mnt.mount_point, -1);
}
}
}
}
private void set_app_page_state(){
@ -1145,10 +1189,8 @@ public class RestoreWindow : Gtk.Dialog{
//refresh treeview
refresh_tv_exclude();
}
private void btn_restore_clicked(){
//check if backup device is online
if (!check_backup_device_online()) { return; }
@ -1226,6 +1268,14 @@ public class RestoreWindow : Gtk.Dialog{
App.exclude_list_restore.add("/boot/*");
}
//display and confirm mount points ------------
if (!radio_sys.active){
if (show_mount_list() != Gtk.ResponseType.OK){
return;
}
}
//last option to quit - show disclaimer ------------
if (show_disclaimer() == Gtk.ResponseType.YES){
@ -1278,14 +1328,13 @@ public class RestoreWindow : Gtk.Dialog{
no_mount_points_set_by_user = false;
App.mount_list.add(new MountEntry(pi,mount_point));
if (mount_point == "/"){
App.restore_target = pi;
break;
}
}
}
if (App.restore_target == null){
//no root mount point was set by user
@ -1373,6 +1422,52 @@ public class RestoreWindow : Gtk.Dialog{
return response;
}
private int show_mount_list(){
string msg = _("Following mounts will be used for restored system:") + "\n\n";
int max_mount = _("Mount").length;
int max_dev = _("Device").length;
foreach(MountEntry mnt in App.mount_list){
string symlink = "";
foreach(string sym in mnt.device.symlinks){
if (sym.has_prefix("/dev/mapper/")){
symlink = sym.replace("/dev/mapper/","");
}
}
string dev_name = mnt.device.device.replace("/dev/","") + ((symlink.length > 0) ? " (" + symlink + ")" : "");//
if (dev_name.length > max_dev){ max_dev = dev_name.length; }
if (mnt.mount_point.length > max_mount){ max_mount = mnt.mount_point.length; }
}
msg += "<tt>";
msg += "<b>";
msg += ("%%-%ds %%-%ds\n\n".printf(max_dev, max_mount)).printf(_("Device"),_("Mount"));
msg += "</b>";
foreach(MountEntry mnt in App.mount_list){
string symlink = "";
foreach(string sym in mnt.device.symlinks){
if (sym.has_prefix("/dev/mapper/")){
symlink = sym.replace("/dev/mapper/","");
}
}
msg += ("%%-%ds %%-%ds\n\n".printf(max_dev, max_mount)).printf(mnt.device.device.replace("/dev/","") + ((symlink.length > 0) ? " (" + symlink + ")" : ""), mnt.mount_point);
}
msg += "</tt>";
msg += "\n" + _("Click OK to continue") + "\n";
var dialog = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, msg);
dialog.set_title(_("Confirm Mounts"));
dialog.set_default_size (200, -1);
dialog.set_transient_for(this);
dialog.set_modal(true);
int response = dialog.run();
dialog.destroy();
return response;
}
private void btn_cancel_clicked(){
App.unmount_target_device();
this.response(Gtk.ResponseType.CANCEL);

View File

@ -1134,7 +1134,7 @@ namespace TeeJee.Devices{
return list;
}
public static string create_fstab_file(FsTabEntry[] fstab_entries, bool keep_comments_and_empty_lines = true){
string text = "";
foreach(FsTabEntry entry in fstab_entries){

View File

@ -18,11 +18,11 @@ long_line_column=80
[files]
current_page=2
FILE_NAME_0=101697;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FMain.vala;0;4
FILE_NAME_1=23341;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FMainWindow.vala;0;4
FILE_NAME_2=25124;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FRestoreWindow.vala;0;4
FILE_NAME_0=26322;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FMain.vala;0;4
FILE_NAME_1=9360;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FMainWindow.vala;0;4
FILE_NAME_2=19883;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FRestoreWindow.vala;0;4
FILE_NAME_3=844;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FSettingsWindow.vala;0;4
FILE_NAME_4=12263;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FUtility.vala;0;4
FILE_NAME_4=26647;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FUtility.vala;0;4
FILE_NAME_5=13;Sh;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Finstaller%2Finstall.sh;0;4
FILE_NAME_6=0;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FAboutWindow.vala;0;4
FILE_NAME_7=946;Make;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2Fmakefile;0;4

File diff suppressed because it is too large Load Diff