#!/usr/bin/env p"ython # -*- coding: iso-8859-1 -*- # FSArchiver is a system tool that allows you to save the contents of a # file system to a compressed archive file. The file system can be restored # on a partition which has a different size and it can be restored on a # different file system. # Unlike tar/dar, FSArchiver also creates the file system when it extracts # the data to partitions. # Everything is checksummed in the archive in order to protect the data. If # the archive is corrupt, you just lose the current file, not the whole archive. # # It is possible to make consistent backups met fsarchiver if you are using LVM ! # see http://www.system-rescue-cd.org/lvm-guide-en/Making-consistent-backups-with-LVM/ # # voor de restore wordt geen snapshot gebruikt ! # wanneer een snapshot gebruikt wordt dan heb je minstens 6G nodig om de logische snapshot = mysnap te creëren op je volumegroup ! # het is dezelfde volumegroep die gebruikt wordt als voor alle te backuppen logische volumen ! # To start this GUI application , you need root rights ! # """ A GUI for fsarchiver using Python3 and Gtk3.0 Author: Franz Ulenaers Version: 1.0 Date: 2017/10/12 """ import gi, os, time, threading gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk global printdone, intervals printdone = 1 intervals = ( ('uren', 3600), ('minuten', 60), ('seconden', 1), ) def display_time(seconds, granularity=3): result = [] for name, count in intervals: value = seconds // count if value: seconds -= value * count if value == 1: name = name.rstrip('s') result.append("{} {}".format(value, name)) return ', '.join(result[:granularity]) class ArchiverGUI(object): def __init__(self): window = Gtk.Window() window.connect("destroy", Gtk.main_quit) vbox = Gtk.VBox(homogeneous=False, spacing=3, expand=False) g = Gtk.Grid() g.set_border_width(10) g.set_row_spacing(5) g.set_column_spacing(5) vbox.add(g) offset = 0 frame = self.new_frame(g, offset, 7) label = Gtk.Label() label.set_markup('Backup een bestandssysteem met fsarchiver') g.attach(label, 0, 0, 2, 1) labels = [" Bestandsystemen te archiveren:", " als snapshot:", " Foldernaam voor gearchiveerd bestand:", " Gearchiveerd bestandsnaam:", " Compressie nummer:", " Aantal cpus/threads:", " Splitsen in aantal blokken van 1G"] for i in range(7): label = Gtk.Label() label.set_markup(labels[i]) g.attach(label, 0, 1 + i, 1, 1) self.dev_list = self.get_device_labels() self.fs_to_archive = Gtk.ComboBoxText.new_with_entry() for d in self.dev_list: self.fs_to_archive.append_text(d) self.fs_to_archive.connect("changed", self.set_default_archive_filename) g.attach(self.fs_to_archive, 1, 1, 1, 1) self.check_snapshot = Gtk.CheckButton("Snapshot") self.check_snapshot.connect("toggled", self.on_snapshot_toggled) self.check_snapshot.set_active(False) g.attach(self.check_snapshot, 1, 2, 1, 1) self.archive_file_path = Gtk.FileChooserButton() self.archive_file_path.set_title("Directory in which to save archive") self.archive_file_path.set_current_folder("/") self.archive_file_path.set_action(Gtk.FileChooserAction.SELECT_FOLDER) g.attach(self.archive_file_path, 1, 3, 1, 1) self.create_archive_filename = Gtk.Entry() g.attach(self.create_archive_filename, 1, 4, 1, 1) self.compression_level = Gtk.ComboBoxText() for i in range(1, 10): self.compression_level.append_text(str(i)) g.attach(self.compression_level, 1, 5, 1, 1) self.number_of_threads = Gtk.ComboBoxText() for i in range(1, 6): self.number_of_threads.append_text(str(i)) g.attach(self.number_of_threads, 1, 6, 1, 1) self.number_of_blocks = Gtk.ComboBoxText() for i in range(1, 7): self.number_of_blocks.append_text(str(i)) g.attach(self.number_of_blocks, 1, 7, 1, 1) #============================ offset = 8 frame = self.new_frame(g, offset, 5) label = Gtk.Label() label.set_markup('Terugzetten gearchiveerd bestandssysteem') g.attach(label, 0, offset, 2, 1) labels = ["Archiveer bestandsnaam:", "Positie in gearchiveerd bestand:", "Terugzetten van bestandssysteem:"] for i in range(3): label = Gtk.Label() label.set_markup(labels[i]) g.attach(label, 0, offset + 1 + i, 1, 1) self.restore_archive_filename = Gtk.FileChooserButton() self.restore_archive_filename.set_title("Bestand bevat gearchiveerd bestandssysteem:") self.restore_archive_filename.set_current_folder("/") self.restore_archive_filename.connect("file-set", self.show_info_window) g.attach(self.restore_archive_filename, 1, offset + 1, 1, 1) self.archive_position = Gtk.ComboBoxText.new_with_entry() self.archive_position.append_text("0") g.attach(self.archive_position, 1, offset + 2, 1, 1) self.destination_filesystem = Gtk.ComboBoxText.new_with_entry() for d in self.dev_list: self.destination_filesystem.append_text(d) g.attach(self.destination_filesystem, 1, offset + 3, 1, 1) #============================ offset = 13 frame = self.new_frame(g, offset, 3) btn_box = Gtk.HButtonBox() frame.add(btn_box) btn_box.set_layout(Gtk.ButtonBoxStyle.SPREAD) btn = Gtk.Button.new_from_stock(Gtk.STOCK_QUIT) btn.connect("clicked", Gtk.main_quit) btn_box.add(btn) btn = Gtk.Button.new_from_stock(Gtk.STOCK_EXECUTE) btn.connect("clicked", self.gather_the_info) btn_box.add(btn) #============================ offset = 16 #frame = self.new_frame(g,offset,3) self.status_label = Gtk.Label(label="Hier komt de status") #frame.add(self.status_label) g.attach(self.status_label, 0, 16, 4, 1) #============================ window.add(vbox) window.show_all() self.info_window = Gtk.Dialog("Gearchiveerde Informatie") c = self.info_window.get_content_area() self.archive_info = Gtk.TextView() c.add(self.archive_info) a = self.info_window.get_action_area() btn = Gtk.Button.new_from_stock(Gtk.STOCK_CLOSE) btn.connect("clicked", lambda x: self.info_window.hide()) a.add(btn) # --------------------------------- def on_snapshot_toggled(self, button): value = button.get_active() self.check_snapshot.set_active(value) def display_time(seconds, granularity=3): result = [] for name, count in intervals: value = seconds // count if value: seconds -= value * count if value == 1: name = name.rstrip('s') result.append("{} {}".format(value, name)) return ', '.join(result[:granularity]) # ---------------------------------- def new_frame(self, grid, top, height): frame = Gtk.Frame() # frame.set_shadow_type(Gtk.ShadowType.ETCHED_IN) grid.attach(frame, 0, top, 3, height) return frame # --------------------------------- def gather_the_info(self, widget): global printdone global display_time starttime = time.strftime('%H:%M:%S', time.localtime()) target = self.fs_to_archive.get_active_text() target = target.strip() try: archive_name = self.restore_archive_filename.get_filename() except: archive_name = "" if target: if self.check_snapshot.get_active(): my_cmd0 = "sudo lvcreate -L 6G -s -n mysnap " + target my_cmd2 = "sudo lvremove -vf " + target l=target.split("/") #print("l 0 =",l[0]) #print("l 1 =",l[1]) #print("l 2 =",l[2]) #print("l 3 =",l[3]) ll = l[3].split("-") target2 = "/"+l[1]+"/"+l[2]+"/"+ll[0]+"-"+"mysnap" #print("target2 =",target2) else: target2 = target path = self.archive_file_path.get_filename() filename = self.create_archive_filename.get_text() + "-" + time.strftime("%Y%m%d%H%M") + ".fsa" compression_level = self.compression_level.get_active() + 1 thread_count = self.number_of_threads.get_active() + 1 block_count = (self.number_of_blocks.get_active() + 1)*1000 my_cmd = "sudo fsarchiver -A -z " + str(compression_level) + \ " -s " + str(block_count) + \ " -j " + str(thread_count) + " savefs " + path + \ "/" + filename + " " + target2 #print ("my_cmd0 =",my_cmd0) #print ("my_cmd = ",my_cmd) #print ("my_cmd2 =",my_cmd2) elif archive_name: position = self.archive_position.get_active_text() destination = self.destination_filesystem.get_active_text() my_cmd = "sudo fsarchiver restfs " + archive_name + \ " id=" + position + ",dest=" + destination #print ("my_cmd0 = ",my_cmd0) #print ("my_cmd = ",my_cmd) #print ("my_cmd2 = ",my_cmd2) if self.check_snapshot.get_active(): self.my_cmd = my_cmd0 + " && " + my_cmd + " && " + my_cmd2 else: self.my_cmd = my_cmd print ("my_cmd = ",my_cmd) self.archiver_busy_flag = 1 t = threading.Thread(target=self.do_my_cmd) t.start() start_time = time.strftime('%H:%M:%S') num_sec = 0 while self.archiver_busy_flag: while Gtk.events_pending(): Gtk.main_iteration_do(False) self.status_label.set_text("Start: " + start_time + " Run time: " + display_time(num_sec, 3) + " running") time.sleep(1) num_sec += 1 if self.archiver_busy_flag == 0: self.status_label.set_text("Start: " + start_time + " Run time: " + display_time(num_sec, 3) + " Done !") time.sleep(1) while printdone == 0: print ("fsarchiver commando : " + self.status_label.get_text()) printdone = 1 # # --------------------------------- def do_my_cmd(self): global printdone os.system(self.my_cmd) self.archiver_busy_flag = 0 printdone = 0 # --------------------------------- def show_info_window(self, widget): target = self.restore_archive_filename.get_filename() print ("Gearchiveerde informatie van bestand = ", target) my_cmd = 'sudo fsarchiver archinfo ' + target + ' 2>&1' archinfo_msg = '' print ("archinfo cmd = ", my_cmd) archinfo = os.popen(my_cmd, 'r') line = archinfo.readline() print (line) knt = 1 while line: archinfo_msg = archinfo_msg + line line = archinfo.readline() print (line) knt += 1 if knt == 3: words = line.split(' ') try: archive_filecount = int(words[2]) for i in range(archive_filecount): self.archive_position.append_text(str(i + 100)) except: continue b = self.archive_info.get_buffer() b.set_text(archinfo_msg) self.info_window.show_all() # --------------------------------- def get_device_labels(self): blkid = os.popen('sudo blkid -c /dev/null', 'r') dev_list = {} line = blkid.readline() while (line): mine = {} line = line.replace('/dev', 'DEVICE=/dev') line = line.replace(':', ' ') line = line.split(' ') for l in line: if l.strip(): m = l.split('=') m[1] = m[1].replace('"', ' ') mine[m[0]] = m[1].strip() break try: x = mine['LABEL'] except: x = 'none' dev_list[mine['DEVICE']] = x line = blkid.readline() return dev_list # --------------------------------- def set_default_archive_filename(self, widget): f = self.fs_to_archive.get_active_text() self.create_archive_filename.set_text(self.dev_list[f]) # =============================== if __name__ == "__main__": app = ArchiverGUI() Gtk.main()