#!/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()