feat: x3-backup v1.0.0 initial release
GTK3 backup/snapshot tool using rsync backend. Features: - rsync-based snapshots with hardlink delta for space efficiency - Snapshot sidebar with date-sorted list - Full file browser with permissions display (name, size, perms, mtime) - Right-click context menu: Restore file/dir with sudo prompt - System tray icon: backup status, context menu (show/backup/settings/quit) - Menu system: File, Backup, System, Help - Settings dialog: backup destination, source path, retention, exclusions - Cronjob management: install/remove scheduled backups - Live Log tab: real-time rsync output during backup - History Log tab: full log file viewer with color-coded entries - System Backup mode: full root filesystem backup - System Restore mode: restore entire system from snapshot - CLI mode: --backup, --system-backup for cron/headless use - /mnt always excluded from backups - Preserves permissions, ACLs, xattrs (-aAX flags) - Log file: ~/.config/x3-backup/x3-backup.log - Config: ~/.config/x3-backup/settings.json - uninstall.sh for clean removal
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "config.h"
|
||||
#include "rsync_manager.h"
|
||||
#include "snapshot_manager.h"
|
||||
#include "main_window.h"
|
||||
|
||||
static FILE* log_file = nullptr;
|
||||
static bool log_to_stdout = false;
|
||||
|
||||
static std::string get_log_path() {
|
||||
const char* home = getenv("HOME");
|
||||
if (!home) home = ".";
|
||||
std::string dir = std::string(home) + "/.config/x3-backup";
|
||||
std::string cmd = "mkdir -p \"" + dir + "\"";
|
||||
(void)system(cmd.c_str());
|
||||
return dir + "/x3-backup.log";
|
||||
}
|
||||
|
||||
static void log_handler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer) {
|
||||
const char* level_str = "INFO";
|
||||
if (level & G_LOG_LEVEL_WARNING) level_str = "WARN";
|
||||
if (level & G_LOG_LEVEL_CRITICAL) level_str = "CRIT";
|
||||
if (level & G_LOG_LEVEL_ERROR) level_str = "ERROR";
|
||||
|
||||
time_t now = time(nullptr);
|
||||
struct tm* t = localtime(&now);
|
||||
char timebuf[32];
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", t);
|
||||
|
||||
char line[2048];
|
||||
snprintf(line, sizeof(line), "[%s] [%s] %s: %s\n", timebuf, level_str, domain ? domain : "app", message);
|
||||
|
||||
if (log_to_stdout) {
|
||||
fputs(line, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
if (log_file) {
|
||||
fputs(line, log_file);
|
||||
fflush(log_file);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_logging(bool cli_mode) {
|
||||
const char* env_log = g_getenv("X3_BACKUP_LOG");
|
||||
if (env_log && strcmp(env_log, "1") == 0) {
|
||||
log_to_stdout = true;
|
||||
}
|
||||
|
||||
if (cli_mode) {
|
||||
log_to_stdout = true;
|
||||
}
|
||||
|
||||
std::string path = get_log_path();
|
||||
log_file = fopen(path.c_str(), "a");
|
||||
if (!log_file) {
|
||||
g_warning("Cannot open log file: %s", path.c_str());
|
||||
}
|
||||
|
||||
g_log_set_handler("x3-backup", (GLogLevelFlags)(G_LOG_LEVEL_MASK), log_handler, nullptr);
|
||||
g_log_set_handler(nullptr, (GLogLevelFlags)(G_LOG_LEVEL_MASK), log_handler, nullptr);
|
||||
|
||||
g_message("=== x3-backup started ===");
|
||||
g_message("Log file: %s", path.c_str());
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
bool system_mode = false;
|
||||
bool backup_now = false;
|
||||
bool show_help = false;
|
||||
bool cli_mode = false;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--system-backup") == 0) {
|
||||
system_mode = true;
|
||||
backup_now = true;
|
||||
cli_mode = true;
|
||||
} else if (strcmp(argv[i], "--backup") == 0) {
|
||||
backup_now = true;
|
||||
cli_mode = true;
|
||||
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
||||
show_help = true;
|
||||
} else if (strcmp(argv[i], "--log") == 0) {
|
||||
log_to_stdout = true;
|
||||
}
|
||||
}
|
||||
|
||||
setup_logging(cli_mode);
|
||||
|
||||
if (show_help) {
|
||||
g_print("x3-Backup - GTK3 Backup/Snapshot Tool\n\n");
|
||||
g_print("Usage: x3-backup [OPTIONS]\n\n");
|
||||
g_print("Options:\n");
|
||||
g_print(" --backup Create a backup immediately and exit\n");
|
||||
g_print(" --system-backup Create a full system backup and exit\n");
|
||||
g_print(" --log Print log to stdout\n");
|
||||
g_print(" --help, -h Show this help\n\n");
|
||||
g_print("Without options, x3-backup starts in GUI mode with system tray.\n\n");
|
||||
g_print("Log file: ~/.config/x3-backup/x3-backup.log\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Config config;
|
||||
config.load();
|
||||
|
||||
if (backup_now) {
|
||||
if (system_mode) {
|
||||
config.set_system_backup_mode(true);
|
||||
config.settings().source_path = "/";
|
||||
g_message("System backup mode: backing up entire system");
|
||||
}
|
||||
|
||||
RsyncManager rsync(config);
|
||||
SnapshotManager snapshots(config, rsync);
|
||||
|
||||
g_message("Starting backup...");
|
||||
snapshots.cleanup_old_snapshots();
|
||||
std::string ts = snapshots.create_snapshot(system_mode ? "System backup" : "Manual backup");
|
||||
if (!ts.empty()) {
|
||||
g_message("Backup completed: %s", ts.c_str());
|
||||
} else {
|
||||
g_warning("Backup failed!");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MainWindow window(config);
|
||||
window.run();
|
||||
|
||||
g_message("=== x3-backup exiting ===");
|
||||
if (log_file) fclose(log_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user