1. Overview
The Main class is the central runtime controller of BastionGuard Backup. It coordinates application initialization, system discovery, snapshot creation, snapshot restoration, configuration persistence, exclusion rules, scheduling, device management, BTRFS operations, RSYNC tasks, logging, and cleanup.
The class supports both graphical and command-line execution. It maintains the global operational state used by the backup engine and delegates specialized operations to internal components such as:
- SnapshotRepo – snapshot repository discovery, mounting, loading, validation, and retention
- Snapshot – snapshot metadata, tags, control files, restoration, and deletion
- RsyncTask – RSYNC-based backup and restore operations
- RsyncSpaceCheckTask – estimation of required incremental snapshot space
- DeleteFileTask – tracked deletion of RSYNC snapshots
- Device – block-device discovery, mounting, unmounting, and LUKS unlocking
- Subvolume – BTRFS subvolume detection, metadata, snapshot restoration, and deletion
- FsTabEntry – parsing and rewriting of
/etc/fstab - CryptTabEntry – parsing and rewriting of
/etc/crypttab - AppExcludeEntry – application-specific restore exclusions
- CronTab – scheduled snapshot job management
- LinuxDistro – Linux distribution detection and bootloader command selection
- AppLock – single-instance execution protection
2. Class Definition and Global State
The class derives from GLib.Object:
public class Main : GLib.Object
A global flag tracks whether GTK has been initialized:
public bool GTK_INITIALIZED = false;
The class contains most of the mutable runtime state of the backup application. This includes:
- Application and configuration paths
- Backup repository state
- Detected partitions and system devices
- Snapshot scheduling configuration
- Backup and restore exclusion lists
- Command-line parameters
- Thread execution state
- Restore target mappings
- BTRFS subvolume and quota information
- Logging paths and application lock state
3. Application Paths
The class maintains several paths used during startup and runtime:
app_path– directory containing the running executableshare_folder– shared application data directoryapp_conf_path– active JSON configuration pathapp_conf_path_old– legacy configuration pathapp_conf_path_default– packaged default configurationmount_point_app– process-specific temporary mount rootmount_point_restore– root mount point used for external restoration
The normal configuration paths are:
/etc/bastionguard-backup/bastionguard-backup.json
/etc/bastionguard-backup.json
The process-specific mount directory is created using the current process ID:
/run/bastionguard-backup/<pid>
This isolates temporary mounts created by different application processes.
4. Snapshot Modes
BastionGuard Backup supports two snapshot engines:
- BTRFS mode – creates native BTRFS subvolume snapshots
- RSYNC mode – creates filesystem copies with hard-link reuse between snapshots
The active mode is stored in:
public bool btrfs_mode = true;
Additional BTRFS options control whether the @home subvolume is included:
include_btrfs_home_for_backupinclude_btrfs_home_for_restore
The application also records whether the installed btrfs-progs version supports recursive subvolume deletion:
public static bool btrfs_version__can_recursive_delete = false;
5. Snapshot Scheduling
The class stores independent scheduling flags for:
- Boot snapshots
- Hourly snapshots
- Daily snapshots
- Weekly snapshots
- Monthly snapshots
Default retention counts are:
Monthly: 2
Weekly: 3
Daily: 5
Hourly: 6
Boot: 5
The computed scheduled property returns true when at least one schedule is enabled and the system is not running as a live environment.
6. Thread and Task State
Long-running operations are tracked through shared state variables:
thread_restore_runningandthread_restore_successthread_delete_runningandthread_delete_successthread_subvol_info_runningandthread_subvol_info_successthr_successthr_retvalthr_timeout_activeprogress_text
The principal task objects are:
RsyncTask task
DeleteFileTask delete_file_task
RsyncSpaceCheckTask space_check_task
Background operations periodically process GTK events to keep the graphical interface responsive.
7. Constructor and Startup Sequence
7.1 Main Constructor
public Main(string[] args, bool gui_mode)
The constructor performs the primary application startup sequence.
The initialization flow is:
- Create the process-specific runtime directory
- Parse early command-line arguments
- Initialize GUI state when running graphically
- Remove obsolete BTRFS helper installations
- Create a session log
- Detect the Linux distribution
- Verify required external commands
- Detect BTRFS command capabilities
- Create the application lock
- Resolve application and shared-data paths
- Initialize repositories, collections, and task objects
- Detect partitions and system devices
- Detect encrypted user directories
- Load the application configuration
- Initialize application icons
7.2 Graphical Mode
When gui_mode is enabled, the class creates a temporary parent window:
parent_window = new Gtk.Window();
In graphical mode, app_mode remains empty. A non-empty app_mode identifies command-line operations.
7.3 Single-Instance Lock
The application creates an AppLock named:
bastionguard-backup
If another incompatible operation already owns the lock:
- GUI mode displays a dedicated
BackupInProgressDialog - Command-line mode exits after the condition has been logged
This prevents simultaneous backup, delete, or restore operations from modifying the repository concurrently.
8. Session Logging
Session logs are stored in:
/var/log/bastionguard-backup
The log filename contains the local date, time, and execution mode:
YYYY-MM-DD_HH-MM-SS_gui.log
YYYY-MM-DD_HH-MM-SS_backup.log
YYYY-MM-DD_HH-MM-SS_restore.log
The directory is created automatically when missing. Existing files with the same generated name are removed before the new DataOutputStream is created.
9. Dependency Validation
9.1 check_dependencies()
public bool check_dependencies(out string msg)
The application verifies that the following commands are available:
rsync
/sbin/blkid
df
mount
umount
fuser
crontab
cp
rm
touch
ln
sync
run-parts
Missing commands are collected into a formatted diagnostic message.
In GUI mode, missing dependencies are displayed through a GTK message box. In command-line mode, the error is logged before the application exits.
10. User Session Environment
10.1 setup_env()
public static void setup_env()
This static method copies graphical-session environment variables from the spawning user process into the current process.
The copied variables include:
GTK_THEMEDISPLAYXAUTHORITYDBUS_SESSION_BUS_ADDRESS
For Wayland sessions, the method also processes:
WAYLAND_DISPLAYXDG_RUNTIME_DIR
This is primarily required when the application runs with elevated privileges but must still access the active user’s graphical session.
11. BTRFS Version Detection
11.1 get_btrfs_version_array()
The private version parser executes:
btrfs --version
It searches the output for a line containing:
btrfs-progs v
The numeric version components are split and converted into an integer array.
11.2 Recursive Delete Capability
public void check_btrfs_version_capabilities()
Recursive BTRFS subvolume deletion is considered supported for:
btrfs-progs > 6.x
btrfs-progs >= 6.12
The resulting capability is stored in:
btrfs_version__can_recursive_delete
12. Legacy BTRFS Helper Removal
12.1 check_and_remove_timeshift_btrfs()
The application checks for an obsolete executable named:
bastionguard-backup-btrfs
If found, it executes:
bastionguard-backup-btrfs-uninstall
This removes the legacy helper before the current snapshot implementation is used.
13. BTRFS Layout Validation
13.1 Current System Layout
public bool check_btrfs_layout_system(Gtk.Window? win = null)
The supported system layout requires an @ root subvolume.
When home snapshots are enabled, an @home subvolume is also required.
Unsupported layouts generate a message explaining that Ubuntu-style @ and @home layouts are expected.
13.2 Target Device Layout
public bool check_btrfs_layout(
Device? dev_root,
Device? dev_home,
bool unlock
)
The method supports:
@and@homeon the same BTRFS filesystem@and@homeon separate BTRFS filesystems- Root-only restoration when home restoration is disabled
Validation is delegated to check_btrfs_volume().
14. Command-Line Mode Detection
14.1 parse_some_arguments()
The constructor performs an early command-line parsing pass to identify the execution mode.
Recognized options include:
--debug– enables command and debug logging--btrfs– forces BTRFS mode--rsync– forces RSYNC mode--check– scheduled backup check--delete– snapshot deletion--delete-all– delete all snapshots--restore– restore a snapshot--clone– clone the current system--create– create an on-demand snapshot--listor--list-snapshots– list snapshots--list-devices– list available devices
15. Live-System Detection
15.1 live_system()
The method reads:
/proc/cmdline
A live environment is detected when the kernel command line contains:
boot=casper
boot=live
The result is cached in _live_system after the first check.
Recovery mode explicitly bypasses live-system restrictions:
if (app_mode == "recovery") {
return false;
}
This permits backup and restore features to remain available in the BastionGuard recovery environment.
16. Encrypted User Directory Detection
16.1 detect_encrypted_dirs()
User accounts are loaded from:
/etc/passwd
System accounts are ignored. For each normal user, the class records:
- Whether the complete home directory is encrypted
- The encrypted home path
- Any encrypted private directories
The results are stored in:
users_with_encrypted_homeencrypted_home_dirsencrypted_private_dirs
These values are later used to prevent decrypted content from being copied into snapshots.
17. Exclusion List Architecture
The class maintains several independent exclusion collections:
exclude_list_user– rules explicitly configured by the userexclude_list_default– mandatory system exclusionsexclude_list_default_extra– optional cache and package exclusionsexclude_list_home– default user-home exclusionsexclude_list_restore– generated restore exclusion listexclude_list_apps– application-specific restore exclusionsexclude_app_names– persisted names of selected applications
18. Default Exclusion Rules
18.1 add_default_exclude_entries()
The method initializes all exclusion lists and adds default paths that must not be copied into a snapshot.
Major excluded filesystem trees include:
/dev/*
/proc/*
/sys/*
/media/*
/mnt/*
/tmp/*
/run/*
/var/run/*
/var/lock/*
/var/lib/docker/*
/lost+found
/swapfile
/snap/*
BastionGuard’s own repository and log paths are excluded to prevent recursive backups:
/bastionguard-backup/*
/bastionguard-backup-btrfs/*
/var/log/bastionguard-backup/*
/var/log/bastionguard-backup-btrfs/*
18.2 Additional Mounted Filesystems
The method parses:
/etc/fstab
Filesystems mounted outside recognized system directories are automatically added to exclude_list_default_extra.
This prevents unrelated data volumes from being included in a system snapshot by default.
18.3 User Cache Exclusions
Common cache and temporary directories are excluded for both root and normal users:
/root/.cache
/root/.thumbnails
/root/.dbus
/root/.gvfs
/root/.local/share/[Tt]rash
/home/*/.cache
/home/*/.thumbnails
/home/*/.dbus
/home/*/.gvfs
/home/*/.local/share/[Tt]rash
18.4 Package Manager Caches
Optional exclusions cover several Linux package managers:
/var/cache/apt/archives/*
/var/cache/pacman/pkg/*
/var/cache/yum/*
/var/cache/dnf/*
/var/cache/eopkg/*
/var/cache/xbps/*
/var/cache/zypp/*
/var/cache/edb/*
18.5 Default Home Exclusions
User home directory contents are excluded by default through:
/root/**
/home/*/**
User-supplied include rules can override these exclusions because user rules are placed earlier in the final RSYNC filter list.
19. Application-Specific Exclusions
19.1 add_app_exclude_entries()
The method clears the global AppExcludeEntry registry and scans the snapshot selected for restoration.
Application data is discovered below:
<snapshot>/localhost/root
<snapshot>/localhost/home
The resulting entries are matched against the persisted exclude_app_names collection.
19.2 Saving Application Selections
public void save_exclude_list_selections()
Enabled application entries are added to exclude_app_names, while disabled entries are removed.
The final application-name list is sorted before being persisted.
20. Backup Exclusion List Generation
20.1 create_exclude_list_for_backup()
The final backup list is assembled in an order designed for RSYNC filter precedence:
- User rules
- Mandatory default rules
- Additional default rules
- Encrypted-directory protections
- Per-user home exclusions
- Common home exclusions
- BastionGuard repository exclusion
User rules are inserted first because RSYNC prioritizes the first matching include or exclude pattern.
20.2 Encrypted Home Protection
Decrypted encrypted-home contents are always excluded:
<user-home>/**
Encrypted private directories receive equivalent protection.
For legacy eCryptfs users, rules target:
/home/.ecryptfs/<username>/***
20.3 Backup Exclusion File
The generated list is saved as:
<snapshot-path>/exclude.list
The file becomes the --exclude-from source used by RSYNC.
21. Restore Exclusion List Generation
21.1 create_exclude_list_for_restore()
The restore exclusion list is rebuilt before each restoration.
It combines:
- User exclusion rules
- Exclusions stored in the snapshot’s
exclude.list - Mandatory default exclusions
- Optional default exclusions when system mirroring is disabled
- Enabled application-specific exclusions
- Home-directory exclusions
User include rules beginning with + are skipped during restoration.
The generated restore list is written to:
<restore-source>/exclude-restore.list
22. Repository Initialization
22.1 initialize()
public void initialize()
The public initialization method delegates repository setup to:
initialize_repo()
22.2 initialize_repo()
The repository-selection strategy depends on the current mode.
Selection priority:
- Use the system disk for BTRFS snapshot creation
- Use the device supplied through a command-line option
- Select a default device during the first run
- Restore the configured repository from stored UUID values
- Unlock the configured encrypted parent device when necessary
In BTRFS backup mode, specifying a separate snapshot device is rejected because snapshots must reside on the relevant BTRFS filesystem.
23. First-Run Behavior
23.1 set_first_run_flag()
During the first run, the application automatically selects a default snapshot engine.
BTRFS mode is selected when:
- The system contains an
@subvolume - The
btrfscommand is available - BTRFS mode was explicitly requested on the command line
Otherwise, RSYNC mode becomes the default.
24. Snapshot Creation Entry Point
24.1 create_snapshot()
public bool create_snapshot(
bool is_ondemand,
Gtk.Window? parent_win
)
This method controls on-demand and scheduled snapshot creation.
The main flow is:
- Validate the BTRFS layout when using BTRFS mode
- Check repository free space
- Remove invalid snapshots when running in command mode
- Create the snapshot directory if missing
- Create an on-demand snapshot or evaluate enabled schedules
- Reload repository metadata
- Apply automatic retention
- Rebuild snapshot symlinks when required
25. Scheduled Snapshot Evaluation
For each enabled schedule, the class obtains the most recent snapshot with the corresponding tag.
A new snapshot is created when:
- No snapshot with that tag exists
- The latest boot snapshot predates the current boot
- The latest hourly snapshot is older than approximately one hour
- The latest daily snapshot is older than approximately one day
- The latest weekly snapshot is older than approximately one week
- The latest monthly snapshot is older than approximately one month
Repository metadata is reloaded after each newly created scheduled snapshot.
26. Snapshot Reuse and Tag Rotation
26.1 create_snapshot_for_tag()
Before creating a new snapshot, the application searches for a sufficiently recent existing snapshot.
If a suitable snapshot already exists, it is reused by adding the requested schedule tag.
This avoids creating duplicate snapshots when several schedule periods become due at approximately the same time.
Supported tags are:
ondemand
boot
hourly
daily
weekly
monthly
27. RSYNC Free-Space Estimation
27.1 get_space_needed_for_rsync_snapshot()
When the stored first-snapshot size is larger than the currently available space, the application performs a dry-run calculation before starting the snapshot.
The method creates a temporary snapshot structure and configures RsyncSpaceCheckTask with:
- The destination snapshot path
- The previous snapshot used for hard-link comparison
- The generated exclusion file
- Relative-path behavior
- Delete and exclusion semantics matching the real snapshot
The resulting total_size represents the estimated additional storage required.
28. RSYNC Snapshot Creation
28.1 create_snapshot_with_rsync()
The RSYNC implementation creates snapshots under:
<repository>/snapshots/YYYY-MM-DD_HH-MM-SS
System files are stored below:
<snapshot>/localhost
28.2 Previous Snapshot Linking
The application selects a previous snapshot as an RSYNC link source.
Selection priority:
- The snapshot named in the
.sync-restorecontrol file - The latest snapshot matching the current system UUID
The source is passed to RSYNC through the task’s link_from_path, enabling unchanged files to be represented by hard links.
28.3 RSYNC Task Configuration
The backup task uses:
- Relative paths
- Verbose progress information
- Deletion of extra destination files
- Deletion of excluded files
- Generated exclusion rules
- An RSYNC operation log
Command-line operations may enable I/O priority reduction through io_nice.
28.4 Snapshot Metadata
After RSYNC completes, the application counts the lines in the RSYNC log and writes the snapshot control file through:
Snapshot.write_control_file()
Stored metadata includes:
- Creation date
- System UUID
- Linux distribution
- Initial tags
- User comments
- File count
- Snapshot engine
29. BTRFS Snapshot Creation
29.1 create_snapshot_with_btrfs()
BTRFS snapshots are created with:
btrfs subvolume snapshot '<source>' '<destination>'
The root subvolume @ is always processed. The @home subvolume is added when home backup is enabled.
Snapshot paths use:
bastionguard-backup-btrfs/snapshots/YYYY-MM-DD_HH-MM-SS
The method contains path corrections for duplicated nested names such as:
/@/@
/@home/@home
Detected system-subvolume metadata is copied into the snapshot control file after creation.
30. Post-Backup Hooks
30.1 run_post_backup_hooks()
After a successful snapshot, executable hooks are loaded from:
/etc/bastionguard-backup/backup-hooks.d
The hook environment contains:
TS_SNAPSHOT_PATH=<snapshot-path>
Hooks are executed with:
run-parts --verbose
If the hook directory does not exist, hook execution is skipped.
31. Snapshot Tags
31.1 set_tags()
Command-line tags are translated as follows:
O = ondemand
B = boot
H = hourly
D = daily
W = weekly
M = monthly
If no valid tags are supplied, the snapshot receives the ondemand tag.
31.2 validate_cmd_tags()
Unknown tag values cause an error and terminate command-line execution.
32. Snapshot Deletion
32.1 delete_begin()
Deletion starts in a dedicated thread named:
delete
The method updates the shared deletion state before launching delete_thread().
32.2 delete_thread()
Every snapshot in delete_list is first marked for deletion.
Deletion behavior depends on the snapshot engine:
- BTRFS – removes the snapshot and its subvolumes
- RSYNC – uses the snapshot’s
DeleteFileTaskand reports elapsed time
Desktop notifications report completed deletions.
33. Restore Device Properties
The following properties expose devices mapped to standard mount points:
dst_root– device mapped to/dst_boot– device mapped to/bootdst_efi– device mapped to/boot/efidst_home– device mapped to/home
The property setters update the corresponding MountEntry inside mount_list.
34. Restore Path Properties
34.1 restore_current_system
A restoration targets the current system when the selected root device matches the active system root by device name or UUID.
34.2 restore_source_path
For a normal restore, the source is the selected snapshot path.
During system cloning, the source is:
/tmp/bastionguard-backup
34.3 restore_target_path
The target is:
/when restoring the active system- The temporary restore mount when restoring another device
34.4 Restore Support Files
The restore process uses:
<restore-source>/rsync-log-restore
<restore-source>/exclude-restore.list
35. Restore Mount-List Initialization
35.1 init_mount_list()
The method builds the target-device mapping from:
- The active system’s
/etc/fstaband/etc/crypttabduring cloning - The selected snapshot’s stored filesystem tables during restoration
Non-system mount points and explicitly excluded paths are ignored.
35.2 Device Resolution
Devices are resolved by:
- Filesystem UUID
- Device path
- Encrypted-parent lookup through
crypttab - LUKS unlocking when a matching encrypted parent is available
Missing devices are represented by mount entries whose device is null.
35.3 Required Mount Entries
The method guarantees that entries exist for:
/
/boot
/home
For cloning, all devices are reset to null so the user must explicitly select clone targets.
Entries are sorted by mount-point path so parent mounts appear before child mounts.
36. Bootloader Options
36.1 init_boot_options()
The initial GRUB device is derived from the target root device and then promoted to its top-level parent disk.
During cloning, the defaults are:
reinstall_grub2 = true
update_initramfs = true
update_grub = true
For Fedora snapshot restoration:
reinstall_grub2 = false
update_initramfs = false
update_grub = true
This avoids unsupported grub2-install operations on Fedora EFI systems.
37. Restore Validation and Execution
37.1 restore_snapshot()
The method validates all required inputs before starting the restore thread.
Checks include:
- The backup device is available
- A snapshot has been selected
- The snapshot is not marked for deletion
- Required BTRFS subvolumes are mounted
- An RSYNC target root device has been selected
- An external target has been mounted when required
Execution is delegated to:
restore_execute_btrfs()restore_execute_rsync()
The caller waits while GTK events continue to be processed.
38. Restore Warning Messages
38.1 get_restore_messages()
The method generates three separate messages:
- A table of devices and mount points that will be modified
- A reboot warning for current-system restoration
- A no-warranty disclaimer
The output can be generated as plain text or GTK markup.
In command-line mode, all messages are written directly to the log.
39. RSYNC Restore Script Generation
39.1 create_restore_scripts()
The method builds two shell scripts:
sh_sync– performs the filesystem synchronizationsh_finish– updates boot configuration, runs hooks, and performs cleanup
The main RSYNC command uses:
rsync -avir --force --delete --delete-before \
--log-file="<restore-log>" \
--exclude-from="<restore-exclude-list>" \
"<source>" "<target>"
Dry-run mode adds:
--dry-run
40. Bootloader and Initramfs Restoration
When restoring to another system, the application bind-mounts:
/dev
/dev/pts
/proc
/run
/sys
These paths are mounted inside the target before executing commands through chroot.
Bootloader commands depend on the target distribution:
- Red Hat family –
grub2-install,grub2-mkconfig, anddracut - Arch family –
grub-install,grub-mkconfig, andmkinitcpio - Debian family –
grub-install,update-grub, andupdate-initramfs
41. Post-Restore Hooks
Restore hooks are loaded from:
/etc/bastionguard-backup/restore-hooks.d
They are executed through:
run-parts --verbose
BTRFS restoration exports:
TS_SNAPSHOT_PATH=<snapshot-path>
Current-system RSYNC restoration forces a reboot after completion.
42. Restore Execution Modes
The class provides four RSYNC execution paths:
restore_current_console()– restore active system from the command linerestore_current_gui()– restore active system through an embedded terminal windowrestore_other_console()– restore or clone another system from the command linerestore_other_gui()– restore or clone another system with tracked graphical progress
Console execution supports verbose and quiet modes. Quiet mode captures stdout and stderr and writes them to the application log.
43. fstab Repair
43.1 fix_fstab_file()
After restoring another system, the target file is loaded from:
<target>/etc/fstab
For each selected mount mapping, the method:
- Adds an entry when missing
- Updates the filesystem UUID
- Updates the filesystem type
- Removes BTRFS
subvoloptions from non-BTRFS devices
System-directory entries that were not explicitly mapped are removed.
Missing mount-point directories are created on the restored filesystem.
44. crypttab Repair
44.1 fix_crypttab_file()
The target encrypted-volume table is loaded from:
<target>/etc/crypttab
Every existing entry receives the nofail option.
Missing entries are created for selected devices located on:
- Direct LUKS containers
- LVM volumes hosted on LUKS containers
Generated entries use:
mapped_name = luks-<UUID>
keyfile = none
options = luks,nofail
45. Filesystem Repair
45.1 check_and_repair_filesystems()
After restoring another system, each mapped target device is checked with:
fsck -y <device>
This operation is skipped when restoring the active system.
46. RSYNC Restore Engine
46.1 restore_execute_rsync()
The RSYNC restore engine:
- Generates synchronization and finishing scripts
- Creates the restore exclusion file
- Deletes old restore logs
- Writes a
.sync-restorecontrol file when restoring the active system - Selects the correct GUI or console execution path
- Unmounts external targets after completion
- Runs filesystem checks when applicable
The .sync-restore file allows a subsequent RSYNC snapshot to link against the recently restored snapshot.
47. BTRFS Restore Engine
47.1 restore_execute_btrfs()
Before restoring the selected snapshot, the method creates or updates a pre-restore snapshot.
Each selected snapshot subvolume is then restored through:
subvol.restore()
The @home subvolume is skipped when home restoration is disabled.
The restored BTRFS snapshot becomes active after the next system reboot.
48. BTRFS Pre-Restore Snapshot
48.1 create_pre_restore_snapshot_btrfs()
The method preserves the current system subvolumes before they are replaced.
If an existing live pre-restore snapshot is found:
- The currently restored
@and optionally@homesubvolumes are deleted - The existing pre-restore snapshot description is updated
Otherwise, active system subvolumes are moved into a new timestamped snapshot directory.
The generated snapshot:
- Receives the
ondemandtag - Is marked as
live - Contains the description
Before restoring ... - Stores subvolume metadata in its control file
49. Configuration Persistence
49.1 save_app_config()
Application settings are serialized as formatted JSON.
Stored values include:
- Backup device UUID
- Encrypted parent-device UUID
- Snapshot engine
- BTRFS home options
- Cron email behavior
- Schedule flags
- Retention counts
- Estimated snapshot size and file count
- Date format
- User exclusion rules
- Selected application exclusions
The JSON generator uses two-space indentation.
49.2 Configuration Keys
backup_device_uuid
parent_device_uuid
do_first_run
btrfs_mode
include_btrfs_home_for_backup
include_btrfs_home_for_restore
stop_cron_emails
schedule_monthly
schedule_weekly
schedule_daily
schedule_hourly
schedule_boot
count_monthly
count_weekly
count_daily
count_hourly
count_boot
snapshot_size
snapshot_count
date_format
exclude
exclude-apps
50. Legacy Configuration Import
50.1 import_timeshift_config_if_available()
The application can import settings from legacy Timeshift or BastionGuard configuration files.
Candidate paths are checked in this order:
/etc/timeshift/timeshift.json
/etc/timeshift.json
/etc/bastionguard-backup/bastionguard-backup.json
/etc/bastionguard-backup.json
The active target configuration is excluded from the import candidates.
Legacy keys such as:
include_btrfs_home
are converted to the newer backup-specific setting.
After import, the normalized configuration is saved to the active BastionGuard path.
51. Configuration Loading
51.1 load_app_config()
If the active configuration does not exist, the method:
- Moves the old BastionGuard configuration when available
- Otherwise copies the packaged default configuration
JSON values are loaded with fallback defaults through the TeeJee JSON helper functions.
A command-line --btrfs or --rsync option overrides the stored snapshot mode.
If no backup UUID is found, additional legacy configuration files are inspected as a fallback.
52. Partition and System-Device Detection
52.1 update_partitions()
The partition list is refreshed through:
Device.get_filesystems()
If the active repository device is rediscovered, its object reference is replaced with the current device instance.
52.2 detect_system_devices()
The class identifies devices mounted at:
/
/home
/boot
/boot/efi
Loop devices are ignored to avoid incorrectly selecting live-system backing volumes.
System BTRFS subvolumes are detected through:
Subvolume.detect_subvolumes_for_system_by_path()
53. Target Device Mounting
53.1 mount_target_devices()
Restore devices are mounted below:
/run/bastionguard-backup/<pid>/restore
The application does not reuse existing mount points because nested target filesystems must be assembled into a single restore tree.
Encrypted devices are unlocked through Device.luks_unlock().
BTRFS mount options include:
subvol=@
subvol=@home
53.2 Unmounting
unmount_target_device() and unmount_device() remove application-created mounts.
A failure can produce a critical GTK dialog and terminate the application when exit_on_error is enabled.
54. Backup Device Validation
54.1 check_btrfs_volume()
The method temporarily mounts the BTRFS top-level filesystem using:
subvolid=0
It verifies that all requested subvolume names exist and then removes the temporary mount.
Encrypted devices may be unlocked when the caller permits it.
54.2 check_device_for_backup()
Rejected devices include:
- Whole-disk objects
- Devices that contain child devices
In BTRFS mode, the device must contain an @ subvolume.
In RSYNC mode, any supported Linux filesystem can be selected.
54.3 try_select_default_device_for_backup()
The method first checks the current repository device.
When BTRFS mode is active and the system contains an @ subvolume, the root BTRFS device is selected automatically.
Otherwise, available partitions are inspected until a valid backup device is found.
55. System-Size Estimation
55.1 estimate_system_size()
The method runs an RSYNC dry run against an empty temporary directory.
The generated statistics are stored in:
Main.first_snapshot_size
Main.first_snapshot_count
If RSYNC reports a zero size, the used-space value of the system root device is used as a fallback.
The result is persisted in the application configuration to avoid repeating the calculation unnecessarily.
56. BTRFS Subvolume Information
56.1 query_subvolume_info()
BTRFS metadata queries run in a dedicated thread.
The operation retrieves:
- Subvolume IDs
- Total referenced bytes
- Unshared bytes
The caller waits while GTK events continue to be processed.
56.2 Subvolume IDs
IDs are obtained with:
btrfs subvolume list '<mount-path>'
Parsed IDs are associated with:
- The active system
@subvolume - The active system
@homesubvolume - Subvolumes belonging to stored snapshots
56.3 BTRFS Quotas
Quota information is queried with:
btrfs qgroup show --raw '<mount-path>'
If --raw is unsupported, the command is retried without it.
The internal quota status can be:
UNKNOWN
DISABLED
ENABLED
When quotas are disabled, repeated quota queries are avoided.
Updated size values are written back to each snapshot’s control file.
57. Cron Scheduling
57.1 cron_job_update()
Cron configuration is skipped on live systems.
Legacy jobs and script files are removed before the current schedule is applied.
The hourly dispatcher is installed as:
0 * * * * root bastionguard-backup --check --scripted
Boot snapshots use:
@reboot root sleep 10m && bastionguard-backup --create --scripted --tags B
The stop_cron_emails option controls whether command output is suppressed by the CronTab helper.
58. Log Retention
58.1 clean_logs()
Session logs are enumerated and sorted alphabetically, which corresponds to chronological order because filenames begin with ISO-style timestamps.
When more than 500 old logs exist, the oldest 100 are deleted.
The active session log is never removed.
59. Application Shutdown
59.1 exit_app()
The controlled shutdown sequence is:
- Save the configuration in GUI mode
- Update Cron jobs
- Unmount restore devices
- Clean old logs
- Release the application lock
- Remove temporary files
- Clean stale process mount points
- Exit with the requested status code
59.2 Stale Mount Cleanup
cleanup_unmount_devices() inspects:
/run/bastionguard-backup
For each process directory, it verifies whether the owning process still exists below /proc.
Stale device mounts are unmounted and their empty directories are removed.
60. Runtime and Security Considerations
- Single-instance protection: the application lock prevents conflicting backup and restore operations.
- Privilege requirements: the class modifies system files, mounts devices, executes bootloader commands, and writes below
/etcand/var/log. - Encrypted-volume support: LUKS devices are detected and unlocked before repository or restore operations.
- Decrypted-data protection: decrypted encrypted-home contents are forcibly excluded from snapshots.
- Restore isolation: external targets are mounted below a process-specific runtime directory.
- Repository recursion prevention: BastionGuard snapshot directories are always excluded from backups.
- Boot safety: restored
fstab,crypttab, initramfs, and GRUB configuration are updated when required. - Pre-restore protection: BTRFS restoration preserves the previous active subvolumes as a recoverable snapshot.
- Hook execution: backup and restore hook directories execute scripts as the application’s privileged user.
- Live-system restrictions: scheduled backups are disabled in ordinary live sessions.
- Filesystem checks: restored external filesystems are checked with
fsck -y. - Log retention: automatic cleanup prevents unbounded growth of session logs.
61. Implementation Considerations
- Centralized mutable state: the class contains a large amount of shared runtime state and acts as both controller and service coordinator.
- Thread synchronization: worker completion is tracked through boolean fields rather than synchronization primitives.
- GTK polling: several operations wait synchronously while repeatedly processing GTK events.
- Shell command construction: restore, BTRFS, GRUB, hook, mount, and cleanup operations rely heavily on dynamically generated shell commands.
- Snapshot creation result:
create_snapshot_for_tag()initializes its return status totrue; the final value may remain true even when the engine returns no snapshot. - Restore exclusion output:
save_exclude_list_for_restore()accepts an output path but writes through the computedrestore_exclude_fileproperty. - BTRFS quota device access: quota queries assume that the home-device reference is available when comparing root and home UUIDs.
- Configuration compatibility: several legacy Timeshift and BastionGuard paths remain supported for migration.
- Legacy naming: some notifications and translated messages still reference TimeShift because the implementation derives from the original project.
- Cron cleanup: the hourly legacy script removal is invoked more than once, which is redundant but normally harmless.
- Version parsing: BTRFS version components are parsed into a fixed-size integer array and assume numeric version segments.
- Hook trust boundary: scripts stored in the backup and restore hook directories execute with the permissions of the application process and must be administrator-controlled.
62. Licensing
The source file is distributed under the GNU General Public License, version 2 or, at the user’s option, any later version.
The original copyright notice identifies:
Copyright 2012-2018 Tony George
<teejeetech@gmail.com>
The software is provided without warranty, including implied warranties of merchantability or fitness for a particular purpose.
