Save backup config during /upgrade

If the user has modified their config within Irssi since the config was
last saved and then runs /upgrade, then we want to save a backup config
(in ~/.irssi/config.clientbackup), which is reloaded upon the upgrade
being done.
This commit is contained in:
Joseph Bisch 2017-09-10 11:56:56 -04:00
commit 9003a57c0a
No known key found for this signature in database
GPG key ID: CF08FAC339AB7E8E
8 changed files with 69 additions and 18 deletions

View file

@ -5,6 +5,7 @@
#define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */ #define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */
#define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */ #define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */
#define IRSSI_HOME_CONFIG_BACKUP "config.clientbackup" /* config file name for upgrades */
#define IRSSI_ABI_VERSION 10 #define IRSSI_ABI_VERSION 10
@ -68,6 +69,7 @@ int g_input_add_full(GIOChannel *source, int priority, int condition,
const char *get_irssi_dir(void); const char *get_irssi_dir(void);
/* return full path for ~/.irssi/config */ /* return full path for ~/.irssi/config */
const char *get_irssi_config(void); const char *get_irssi_config(void);
void set_irssi_config(char *);
/* max. size for %d */ /* max. size for %d */
#define MAX_INT_STRLEN ((sizeof(int) * CHAR_BIT + 2) / 3 + 1) #define MAX_INT_STRLEN ((sizeof(int) * CHAR_BIT + 2) / 3 + 1)

View file

@ -76,6 +76,11 @@ const char *get_irssi_config(void)
return irssi_config_file; return irssi_config_file;
} }
void set_irssi_config(char *path)
{
irssi_config_file = path;
}
static void sig_reload_config(int signo) static void sig_reload_config(int signo)
{ {
reload_config = TRUE; reload_config = TRUE;

View file

@ -26,6 +26,7 @@
#include "net-sendbuffer.h" #include "net-sendbuffer.h"
#include "pidwait.h" #include "pidwait.h"
#include "lib-config/iconfig.h" #include "lib-config/iconfig.h"
#include "settings.h"
#include "chat-protocols.h" #include "chat-protocols.h"
#include "servers.h" #include "servers.h"
@ -58,8 +59,8 @@ void session_upgrade(void)
/* SYNTAX: UPGRADE [<irssi binary path>] */ /* SYNTAX: UPGRADE [<irssi binary path>] */
static void cmd_upgrade(const char *data) static void cmd_upgrade(const char *data)
{ {
CONFIG_REC *session; CONFIG_REC *session, *config;
char *session_file, *str; char *session_file, *config_file, *str;
char *binary; char *binary;
if (*data == '\0') if (*data == '\0')
@ -77,12 +78,19 @@ static void cmd_upgrade(const char *data)
config_write(session, NULL, -1); config_write(session, NULL, -1);
config_close(session); config_close(session);
/* save the config */
config_file = g_strdup_printf("%s/"IRSSI_HOME_CONFIG_BACKUP, get_irssi_dir());
unlink(config_file);
signal_emit("command save", 1, config_file);
/* data may contain some other program as well, like /* data may contain some other program as well, like
/UPGRADE /usr/bin/screen irssi */ /UPGRADE /usr/bin/screen irssi */
str = g_strdup_printf("%s --noconnect --session=%s --home=%s --config=%s", str = g_strdup_printf("%s --noconnect --session=%s --home=%s --config=%s",
binary, session_file, get_irssi_dir(), get_irssi_config()); binary, session_file, get_irssi_dir(), config_file);
g_free(binary); g_free(binary);
g_free(session_file); g_free(session_file);
g_free(config_file);
session_args = g_strsplit(str, " ", -1); session_args = g_strsplit(str, " ", -1);
g_free(str); g_free(str);
@ -315,20 +323,42 @@ static void sig_session_restore(CONFIG_REC *config)
static void sig_init_finished(void) static void sig_init_finished(void)
{ {
CONFIG_REC *session; CONFIG_REC *session, *config;
char *config_file;
if (session_file == NULL) FILE *fp;
return;
if (session_file != NULL) {
session = config_open(session_file, -1); session = config_open(session_file, -1);
if (session == NULL) if (session != NULL) {
return;
config_parse(session); config_parse(session);
signal_emit("session restore", 1, session); signal_emit("session restore", 1, session);
config_close(session); config_close(session);
}
unlink(session_file); unlink(session_file);
}
config_file = g_strdup_printf("%s/"IRSSI_HOME_CONFIG_BACKUP, get_irssi_dir());
if ((fp = fopen(config_file, "r")) != NULL) {
/* load backup */
signal_emit("command reload", 1, config_file);
backupconfig = parse_configfile(config_file);
/* set irssi_config_file back to default so any future saves/reloads behave as expected */
set_irssi_config(g_strdup_printf("%s/"IRSSI_HOME_CONFIG, get_irssi_dir()));
/* load regular config into mainconfig */
signal_emit("command reload", 1, get_irssi_config());
/* setup mainconfig so that data from backup config is saved on next save */
mainconfig->mainnode = backupconfig->mainnode;
mainconfig->cache = backupconfig->cache;
mainconfig->cache_nodes = backupconfig->cache_nodes;
fclose(fp);
}
g_free(config_file);
} }
void session_register_options(void) void session_register_options(void)

View file

@ -34,6 +34,7 @@
#define SETTINGS_AUTOSAVE_TIMEOUT (1000*60*60) /* 1 hour */ #define SETTINGS_AUTOSAVE_TIMEOUT (1000*60*60) /* 1 hour */
CONFIG_REC *mainconfig; CONFIG_REC *mainconfig;
CONFIG_REC *backupconfig = NULL;
static GString *last_errors; static GString *last_errors;
static GSList *last_invalid_modules; static GSList *last_invalid_modules;
@ -673,7 +674,7 @@ static unsigned int file_checksum(const char *fname)
return checksum; return checksum;
} }
static void irssi_config_save_state(const char *fname) void irssi_config_save_state(const char *fname)
{ {
struct stat statbuf; struct stat statbuf;
@ -703,7 +704,7 @@ int irssi_config_is_changed(const char *fname)
config_last_checksum != file_checksum(fname)); config_last_checksum != file_checksum(fname));
} }
static CONFIG_REC *parse_configfile(const char *fname) CONFIG_REC *parse_configfile(const char *fname)
{ {
CONFIG_REC *config; CONFIG_REC *config;
struct stat statbuf; struct stat statbuf;
@ -827,6 +828,9 @@ int settings_save(const char *fname, int autosave)
g_free(str); g_free(str);
} }
signal_emit("setup saved", 2, fname, GINT_TO_POINTER(autosave)); signal_emit("setup saved", 2, fname, GINT_TO_POINTER(autosave));
if (backupconfig != NULL && backupconfig->fname != NULL) {
unlink(backupconfig->fname);
}
return !error; return !error;
} }

View file

@ -51,6 +51,7 @@ typedef struct {
#define iconfig_node_add_list(a, b) config_node_add_list(mainconfig, a, b) #define iconfig_node_add_list(a, b) config_node_add_list(mainconfig, a, b)
extern struct _CONFIG_REC *mainconfig; extern struct _CONFIG_REC *mainconfig;
extern struct _CONFIG_REC *backupconfig;
extern const char *default_config; extern const char *default_config;
/* Functions for handling the "settings" node of Irssi configuration */ /* Functions for handling the "settings" node of Irssi configuration */
@ -123,7 +124,9 @@ void settings_clean_invalid(void);
/* if `fname' is NULL, the default is used */ /* if `fname' is NULL, the default is used */
int settings_reread(const char *fname); int settings_reread(const char *fname);
int settings_save(const char *fname, int autosave); int settings_save(const char *fname, int autosave);
void irssi_config_save_state(const char *fname);
int irssi_config_is_changed(const char *fname); int irssi_config_is_changed(const char *fname);
struct _CONFIG_REC *parse_configfile(const char *fname);
void settings_init(void); void settings_init(void);
void settings_deinit(void); void settings_deinit(void);

View file

@ -364,9 +364,12 @@ static void cmd_save(const char *data)
if (*fname == '\0') if (*fname == '\0')
fname = mainconfig->fname; fname = mainconfig->fname;
if (!irssi_config_is_changed(fname)) if (irssi_config_is_changed(fname) && backupconfig != NULL) {
settings_save_fe(fname); /* config file modified outside irssi and backup config exists */
else { /* must not save and direct user to merge files outside of irssi */
printformat(NULL,NULL, MSGLEVEL_CLIENTNOTICE,
TXT_CONFIG_CONFLICT, fname, backupconfig->fname);
} else if (irssi_config_is_changed(fname)) {
/* config file modified outside irssi */ /* config file modified outside irssi */
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
TXT_CONFIG_MODIFIED, fname); TXT_CONFIG_MODIFIED, fname);
@ -376,6 +379,8 @@ static void cmd_save(const char *data)
keyboard_entry_redirect((SIGNAL_FUNC) settings_save_confirm, keyboard_entry_redirect((SIGNAL_FUNC) settings_save_confirm,
format, 0, g_strdup(fname)); format, 0, g_strdup(fname));
g_free(format); g_free(format);
} else {
settings_save_fe(fname);
} }
cmd_params_free(free_arg); cmd_params_free(free_arg);

View file

@ -279,6 +279,7 @@ FORMAT_REC fecommon_core_formats[] = {
{ "config_saved", "Saved configuration to file $0", 1, { 0 } }, { "config_saved", "Saved configuration to file $0", 1, { 0 } },
{ "config_reloaded", "Reloaded configuration", 1, { 0 } }, { "config_reloaded", "Reloaded configuration", 1, { 0 } },
{ "config_modified", "Configuration file was modified since irssi was last started - do you want to overwrite the possible changes?", 1, { 0 } }, { "config_modified", "Configuration file was modified since irssi was last started - do you want to overwrite the possible changes?", 1, { 0 } },
{ "config_conflict", "Configuration file was modified since irssi was last started and backup config from upgrade exists - please use external merge tool to merge $0 and $1 into $0. Config was not saved.", 2, { 0, 0 } },
{ "glib_error", "{error $0} $1", 2, { 0, 0 } }, { "glib_error", "{error $0} $1", 2, { 0, 0 } },
{ "overwrite_config", "Overwrite config (y/N)?", 0 }, { "overwrite_config", "Overwrite config (y/N)?", 0 },
{ "set_title", "[{hilight $0}]", 1, { 0 } }, { "set_title", "[{hilight $0}]", 1, { 0 } },

View file

@ -244,6 +244,7 @@ enum {
TXT_CONFIG_SAVED, TXT_CONFIG_SAVED,
TXT_CONFIG_RELOADED, TXT_CONFIG_RELOADED,
TXT_CONFIG_MODIFIED, TXT_CONFIG_MODIFIED,
TXT_CONFIG_CONFLICT,
TXT_GLIB_ERROR, TXT_GLIB_ERROR,
TXT_OVERWRITE_CONFIG, TXT_OVERWRITE_CONFIG,
TXT_SET_TITLE, TXT_SET_TITLE,