~teejee2008/timeshift/trunk

« back to all changes in this revision

Viewing changes to src/Core/Main.vala

  • Committer: Tony George
  • Date: 2016-12-26 15:50:17 UTC
  • Revision ID: tony.george.kol@gmail.com-20161226155017-ae30px7sg6znki6u
Console: Added --btrfs and --rsync; BTRFS: Added support for @home on separate disk;

Show diffs side-by-side

added added

removed removed

Lines of Context:
635
635
                return exclude_list_restore;
636
636
        }
637
637
 
 
638
 
638
639
        public bool save_exclude_list_for_backup(string output_path){
639
640
 
640
641
                log_debug("Main: save_exclude_list_for_backup()");
942
943
                                repo.create_symlinks();
943
944
                        }
944
945
                        
945
 
                        log_msg("ok");
 
946
                        //log_msg("OK");
946
947
                }
947
948
                catch(Error e){
948
949
                        log_error (e.message);
999
1000
                                        // tag the backup
1000
1001
                                        backup_to_rotate.add_tag(tag);
1001
1002
        
1002
 
                                        var message = "%s '%s' %s '%s'".printf(
1003
 
                                                _("Snapshot"), backup_to_rotate.name, _("tagged"), tag);
 
1003
                                        var message = _("Tagged snapshot") + " '%s': %s".printf(backup_to_rotate.name, tag);
1004
1004
                                        log_msg(message);
1005
1005
 
1006
1006
                                        return true;
1035
1035
                        OSDNotify.notify_send("TimeShift", message, 10000, "low");
1036
1036
 
1037
1037
                        if (new_snapshot != null){
1038
 
                                message = "%s '%s' %s '%s'".printf(_("Snapshot"), new_snapshot.name, _("tagged"), tag);
 
1038
                                message = _("Tagged snapshot") + " '%s': %s".printf(new_snapshot.name, tag);
1039
1039
                                log_msg(message);
1040
1040
                        }
1041
1041
 
1052
1052
 
1053
1053
        private Snapshot? create_snapshot_with_rsync(string tag, DateTime dt_created){
1054
1054
                
1055
 
                log_msg(_("Creating new backup...") + "(RSYNC)");
 
1055
                log_msg(_("Creating new snapshot...") + "(RSYNC)");
1056
1056
                
1057
1057
                // take new backup ---------------------------------
1058
1058
 
1179
1179
                // write control file
1180
1180
                Snapshot.write_control_file(
1181
1181
                        snapshot_path, dt_created, sys_uuid, current_distro.full_name(),
1182
 
                        tag, cmd_comments, 0, false, false);
 
1182
                        tag, cmd_comments, 0, false, false, App.repo);
1183
1183
 
1184
1184
                // parse log file
1185
1185
                progress_text = _("Parsing log file...");
1190
1190
                // write control file
1191
1191
                var snapshot = Snapshot.write_control_file(
1192
1192
                        snapshot_path, dt_created, sys_uuid, current_distro.full_name(),
1193
 
                        tag, cmd_comments, task.prg_count_total, false, false);
 
1193
                        tag, cmd_comments, task.prg_count_total, false, false, App.repo);
1194
1194
 
1195
1195
                return snapshot;
1196
1196
        }
1207
1207
                }
1208
1208
 
1209
1209
                string time_stamp = dt_created.format("%Y-%m-%d_%H-%M-%S");
1210
 
                string snapshot_dir = repo.snapshots_path;
1211
1210
                string snapshot_name = time_stamp;
1212
 
                string snapshot_path = path_combine(snapshot_dir, snapshot_name);
1213
 
                dir_create(snapshot_path);
 
1211
                string sys_uuid = (sys_root == null) ? "" : sys_root.uuid;
 
1212
                string snapshot_path = "";
1214
1213
                
1215
 
                string sys_uuid = (sys_root == null) ? "" : sys_root.uuid;
1216
 
                Snapshot snapshot_to_link = null;
1217
 
 
1218
1214
                // create subvolume snapshots
1219
1215
                
1220
1216
                foreach(var subvol in sys_subvolumes.values){
1221
1217
 
1222
 
                        string mount_path = repo.mount_path;
1223
 
                        
1224
 
                        if ((subvol.name == "@home") && (subvol.dev_uuid != repo.device.uuid)){
1225
 
                                
1226
 
                                Device.automount_udisks(subvol.dev_uuid, parent_window);
1227
 
 
1228
 
                                var mps = Device.get_device_mount_points(subvol.dev_uuid);
1229
 
                                if (mps.size > 0){
1230
 
                                        mount_path = mps[0].mount_point;
1231
 
                                }
1232
 
                                else{
1233
 
                                        mount_path = "";
1234
 
                                }
1235
 
                        }
1236
 
 
1237
 
                        string cmd = "btrfs subvolume snapshot '%s/%s' '%s/%s' \n".printf(mount_path, subvol.name, snapshot_path, subvol.name);
 
1218
                        snapshot_path = path_combine(repo.mount_paths[subvol.name], "timeshift-btrfs/snapshots/%s".printf(snapshot_name));
 
1219
                        dir_create(snapshot_path, true);
 
1220
                        
 
1221
                        string src_path = path_combine(repo.mount_paths[subvol.name], subvol.name);
 
1222
                        string dst_path = path_combine(snapshot_path, subvol.name);
 
1223
                        
 
1224
                        string cmd = "btrfs subvolume snapshot '%s' '%s' \n".printf(src_path, dst_path);
1238
1225
                        if (LOG_COMMANDS) { log_debug(cmd); }
1239
1226
 
1240
1227
                        string std_out, std_err;
1245
1232
                                log_error(_("Failed to create subvolume snapshot") + ": %s".printf(subvol.name));
1246
1233
                                return null;
1247
1234
                        }
 
1235
                        else{
 
1236
                                log_msg(_("Created subvolume snapshot") + ": %s".printf(dst_path));
 
1237
                        }
1248
1238
                }
1249
1239
 
1250
 
                log_msg(_("Writing control file..."));
 
1240
                //log_msg(_("Writing control file..."));
 
1241
 
 
1242
                snapshot_path = path_combine(repo.mount_paths["@"], "timeshift-btrfs/snapshots/%s".printf(snapshot_name));
1251
1243
                
1252
1244
                // write control file
1253
1245
                var snapshot = Snapshot.write_control_file(
1254
1246
                        snapshot_path, dt_created, sys_uuid, current_distro.full_name(),
1255
 
                        tag, cmd_comments, 0, true, false);
 
1247
                        tag, cmd_comments, 0, true, false, App.repo);
1256
1248
 
1257
1249
                // write subvolume info
1258
1250
                foreach(var subvol in sys_subvolumes.values){
1711
1703
                
1712
1704
                // final check - check if target root device is mounted
1713
1705
 
1714
 
                if (dst_root == null){
1715
 
                        log_error(_("Target device not specified!"));
1716
 
                        return false;
 
1706
                if (btrfs_mode){
 
1707
                        if (repo.mount_paths["@"].length == 0){
 
1708
                                log_error(_("BTRFS device is not mounted") + ": @");
 
1709
                                return false;
 
1710
                        }
 
1711
                        if (repo.mount_paths["@home"].length == 0){
 
1712
                                log_error(_("BTRFS device is not mounted") + ": @home");
 
1713
                                return false;
 
1714
                        }
1717
1715
                }
 
1716
                else{
 
1717
                        if (dst_root == null){
 
1718
                                log_error(_("Target device not specified!"));
 
1719
                                return false;
 
1720
                        }
1718
1721
 
1719
 
                if (!restore_current_system){
1720
 
                        if (mount_point_restore.strip().length == 0){
1721
 
                                log_error(_("Target device is not mounted"));
1722
 
                                return false;
 
1722
                        if (!restore_current_system){
 
1723
                                if (mount_point_restore.strip().length == 0){
 
1724
                                        log_error(_("Target device is not mounted"));
 
1725
                                        return false;
 
1726
                                }
1723
1727
                        }
1724
1728
                }
1725
1729
 
1771
1775
                foreach(var entry in mount_list){
1772
1776
                        if (entry.device == null){ continue; }
1773
1777
 
 
1778
                        if (btrfs_mode){
 
1779
                                if (entry.subvolume_name().length == 0){
 
1780
                                        continue;
 
1781
                                }
 
1782
                        }
 
1783
                        
1774
1784
                        string dev_name = entry.device.full_name_with_parent;
1775
1785
                        if (entry.subvolume_name().length > 0){
1776
1786
                                dev_name = dev_name + "(%s)".printf(entry.subvolume_name());
1797
1807
                foreach(var entry in mount_list){
1798
1808
                        if (entry.device == null){ continue; }
1799
1809
 
 
1810
                        if (btrfs_mode){
 
1811
                                if (entry.subvolume_name().length == 0){
 
1812
                                        continue;
 
1813
                                }
 
1814
                        }
 
1815
                        
1800
1816
                        string dev_name = entry.device.full_name_with_parent;
1801
1817
                        if (entry.subvolume_name().length > 0){
1802
1818
                                dev_name = dev_name + "(%s)".printf(entry.subvolume_name());
1867
1883
        public void restore_execute(){
1868
1884
 
1869
1885
                log_debug("Main: restore_execute()");
1870
 
                
 
1886
 
1871
1887
                try{
1872
1888
 
1873
1889
                        log_debug("source_path=%s".printf(restore_source_path));
2441
2457
                        int ret_val = exec_script_sync(sh_fsck, null, null, false, false, false, true);
2442
2458
                }
2443
2459
        }
 
2460
 
 
2461
        public bool restore_execute_btrfs(Gtk.Window? parent_win){
 
2462
 
 
2463
                log_debug("Main: restore_execute_btrfs()");
 
2464
                
 
2465
                string cmd, std_out, std_err;
 
2466
                
 
2467
                //query_subvolume_info();
 
2468
 
 
2469
                bool ok = create_pre_restore_snapshot_btrfs();
 
2470
                if (!ok){
 
2471
                        return false;
 
2472
                }
 
2473
                
 
2474
                // restore snapshot subvolumes by creating new subvolume snapshots
 
2475
 
 
2476
                foreach(string subvol_name in new string[] { "@","@home" }){
 
2477
                        
 
2478
                        string subvol_path = path_combine(snapshot_to_restore.path, subvol_name);
 
2479
                
 
2480
                        if (dir_exists(subvol_path)){
 
2481
                                string src_path = path_combine(snapshot_to_restore.path, subvol_name);
 
2482
                                string dst_path = path_combine(App.repo.mount_paths[subvol_name], subvol_name);
 
2483
                                cmd = "btrfs subvolume snapshot '%s' '%s'".printf(src_path, dst_path);
 
2484
                                log_debug(cmd);
 
2485
                                int status = exec_sync(cmd, out std_out, out std_err);
 
2486
                                if (status != 0){
 
2487
                                        log_error (std_err);
 
2488
                                        log_error(_("btrfs returned an error") + ": %d".printf(status));
 
2489
                                        log_error(_("Failed to restore system subvolume") + ": %s".printf(subvol_name));
 
2490
                                        return false;
 
2491
                                }
 
2492
                                else{
 
2493
                                        log_msg(_("Restored system subvolume") + ": %s".printf(subvol_name));
 
2494
                                }
 
2495
                        }
 
2496
                }
 
2497
 
 
2498
                log_msg(_("Restore completed without errors"));
 
2499
                if (restore_current_system){
 
2500
                        log_msg(_("Snapshot will become active after system is rebooted."));
 
2501
                }
 
2502
                
 
2503
                return true;
 
2504
        }
 
2505
 
 
2506
        public bool create_pre_restore_snapshot_btrfs(){
 
2507
 
 
2508
                log_debug("Main: create_pre_restore_snapshot_btrfs()");
 
2509
                
 
2510
                string cmd, std_out, std_err;
 
2511
                DateTime dt_created = new DateTime.now_local();
 
2512
                string time_stamp = dt_created.format("%Y-%m-%d_%H-%M-%S");
 
2513
                string snapshot_name = time_stamp;
 
2514
                string snapshot_path = path_combine(App.repo.snapshots_path, snapshot_name);
 
2515
 
 
2516
                /* Note:
 
2517
                 * The @ and @home subvolumes need to be backed-up only if they are in use by the system.
 
2518
                 * If user restores a snapshot and then tries to restore another snapshot before the next reboot
 
2519
                 * then the @ and @home subvolumes are the ones that were previously restored and need to be deleted.
 
2520
                 * */
 
2521
 
 
2522
                bool create_pre_restore_backup = false;
 
2523
 
 
2524
                if (restore_current_system){
 
2525
                        
 
2526
                        // check for an existing pre-restore backup
 
2527
 
 
2528
                        Snapshot snap_prev = null;
 
2529
                        bool found = false;
 
2530
                        foreach(var bak in repo.snapshots){
 
2531
                                if (bak.live){
 
2532
                                        found = true;
 
2533
                                        snap_prev = bak;
 
2534
                                        log_msg(_("Found existing pre-restore snapshot") + ": %s".printf(bak.name));
 
2535
                                        break;
 
2536
                                }
 
2537
                        }
 
2538
 
 
2539
                        if (found){
 
2540
                                //delete system subvolumes
 
2541
                                sys_subvolumes["@"].remove();
 
2542
                                sys_subvolumes["@home"].remove();
 
2543
                                log_msg(_("Deleted system subvolumes: @, @home"));
 
2544
                                
 
2545
                                //update description for pre-restore backup
 
2546
                                snap_prev.description = "Before restoring '%s'".printf(snapshot_to_restore.date_formatted);
 
2547
                                snap_prev.update_control_file();
 
2548
                        }
 
2549
                        else{
 
2550
                                create_pre_restore_backup = true;
 
2551
                        }
 
2552
                }
 
2553
                else{
 
2554
                        create_pre_restore_backup = true;
 
2555
                }
 
2556
 
 
2557
                if (create_pre_restore_backup){
 
2558
 
 
2559
                        log_msg(_("Creating pre-restore snapshot from system subvolumes..."));
 
2560
                        
 
2561
                        dir_create(snapshot_path);
 
2562
 
 
2563
                        // move subvolumes ----------------
 
2564
                        
 
2565
                        bool no_subvolumes_found = true;
 
2566
                        
 
2567
                        foreach(string subvol_name in new string[] { "@", "@home" }){
 
2568
                                
 
2569
                                string src_path = path_combine(repo.mount_paths[subvol_name], subvol_name);
 
2570
                                if (!dir_exists(src_path)){
 
2571
                                        log_error(_("Could not find system subvolume") + ": %s".printf(subvol_name));
 
2572
                                        continue;
 
2573
                                }
 
2574
                                
 
2575
                                no_subvolumes_found = false;
 
2576
                                
 
2577
                                string dst_path = path_combine(snapshot_path, subvol_name);
 
2578
                                cmd = "mv '%s' '%s'".printf(src_path, dst_path);
 
2579
                                log_debug(cmd);
 
2580
                                int status = exec_sync(cmd, out std_out, out std_err);
 
2581
                                if (status != 0){
 
2582
                                        log_error (std_err);
 
2583
                                        log_error(_("Failed to move system subvolume to snapshot directory") + ": %s".printf(subvol_name));
 
2584
                                        return false;
 
2585
                                }
 
2586
                                else{
 
2587
                                        log_msg(_("Moved system subvolume to snapshot directory") + ": %s".printf(subvol_name));
 
2588
                                }
 
2589
                        }
 
2590
 
 
2591
                        if (no_subvolumes_found){
 
2592
                                //could not find system subvolumes for backing up(!)
 
2593
                                file_delete(snapshot_path); //cleanup and ignore
 
2594
                                log_error(_("Could not find system subvolumes for creating pre-restore snapshot"));
 
2595
                        }
 
2596
                        else{
 
2597
                                // write control file -----------
 
2598
                                
 
2599
                                var snap = Snapshot.write_control_file(
 
2600
                                        snapshot_path, dt_created, sys_root.uuid, current_distro.full_name(),
 
2601
                                        "ondemand", "", 0, true, false, App.repo);
 
2602
 
 
2603
                                snap.description = "Before restoring '%s'".printf(snapshot_to_restore.date_formatted);
 
2604
                                snap.live = true;
 
2605
                                
 
2606
                                // write subvolume info
 
2607
                                foreach(var subvol in sys_subvolumes.values){
 
2608
                                        snap.subvolumes.set(subvol.name, subvol);
 
2609
                                }
 
2610
                                
 
2611
                                snap.update_control_file(); // save subvolume info
 
2612
 
 
2613
                                log_msg(_("Created pre-restore snapshot") + ": %s".printf(snap.name));
 
2614
                                
 
2615
                                repo.load_snapshots();
 
2616
                        }
 
2617
                }
 
2618
 
 
2619
                return true;
 
2620
        }
2444
2621
        
2445
2622
        //app config
2446
2623