#!/usr/bin/env python3.9
# -*- 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/
#
# 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('<span font="12" weight="bold">Backup een bestandssysteem met fsarchiver</span>')
g.attach(label, 0, 0, 2, 1)
labels = ["<b> Bestandsystemen te archiveren:</b>",
"<b> Foldernaam voor gearchiveerd bestand:</b>",
"<b> Gearchiveerd bestandsnaam:</b>",
"<b> Compressie nummer:</b>",
"<b> Aantal cpus/threads:</b>",
"<b> Splitsen in aantal blokken van 1G</b>"]
for i in range(6):
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.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, 2, 1, 1)
self.create_archive_filename = Gtk.Entry()
g.attach(self.create_archive_filename, 1, 3, 1, 1)
self.compression_level = Gtk.ComboBoxText()
for i in range(1, 23):
self.compression_level.append_text(str(i))
g.attach(self.compression_level, 1, 4, 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, 5, 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, 6, 1, 1)
#============================
offset = 8
frame = self.new_frame(g, offset, 5)
label = Gtk.Label()
label.set_markup('<span font="12" weight="bold">Terugzetten gearchiveerd bestandssysteem</span>')
g.attach(label, 0, offset, 2, 1)
labels = ["<b>Archiveer bestandsnaam:</b>",
"<b>Positie in gearchiveerd bestand:</b>",
"<b>Terugzetten van bestandssysteem:</b>"]
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 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:
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 + " " + target
#print ("my_cmd = ",my_cmd)
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_cmd = ",my_cmd)
self.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()
#!/usr/bin/env python3.9
# -*- 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/
#
# 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('<span font="12" weight="bold">Backup een bestandssysteem met fsarchiver</span>')
g.attach(label, 0, 0, 2, 1)
labels = ["<b> Bestandsystemen te archiveren:</b>",
"<b> Foldernaam voor gearchiveerd bestand:</b>",
"<b> Gearchiveerd bestandsnaam:</b>",
"<b> Compressie nummer:</b>",
"<b> Aantal cpus/threads:</b>",
"<b> Splitsen in aantal blokken van 1G</b>"]
for i in range(6):
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.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, 2, 1, 1)
self.create_archive_filename = Gtk.Entry()
g.attach(self.create_archive_filename, 1, 3, 1, 1)
self.compression_level = Gtk.ComboBoxText()
for i in range(1, 23):
self.compression_level.append_text(str(i))
g.attach(self.compression_level, 1, 4, 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, 5, 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, 6, 1, 1)
#============================
offset = 8
frame = self.new_frame(g, offset, 5)
label = Gtk.Label()
label.set_markup('<span font="12" weight="bold">Terugzetten gearchiveerd bestandssysteem</span>')
g.attach(label, 0, offset, 2, 1)
labels = ["<b>Archiveer bestandsnaam:</b>",
"<b>Positie in gearchiveerd bestand:</b>",
"<b>Terugzetten van bestandssysteem:</b>"]
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 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:
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 + " " + target
#print ("my_cmd = ",my_cmd)
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_cmd = ",my_cmd)
self.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()