From 02c9cb11c4d22b8b4c3f185229a68ece3aee59e5 Mon Sep 17 00:00:00 2001 From: Andreas Kempe Date: Fri, 24 Jan 2020 23:09:12 +0100 Subject: [PATCH] configuration: add keepconf option Add configuration option keepconf that stops xbps from overwriting unchanged configuration files. If keepconf=true, xbps will store the new configuration as .new- instead of overwriting unchanged configuration files. --- data/xbps.conf | 14 +++++ data/xbps.d.5 | 11 +++- include/xbps.h.in | 8 +++ lib/conf.c | 11 ++++ lib/initend.c | 1 + lib/package_config_files.c | 13 +++-- tests/xbps/libxbps/shell/conf_files_test.sh | 62 +++++++++++++++++++++ 7 files changed, 115 insertions(+), 5 deletions(-) mode change 100644 => 100755 tests/xbps/libxbps/shell/conf_files_test.sh diff --git a/data/xbps.conf b/data/xbps.conf index 3a594ad5..d16266bd 100644 --- a/data/xbps.conf +++ b/data/xbps.conf @@ -71,6 +71,20 @@ # preserve=/etc/file # preserve=/etc/dir/*.conf +## PRESERVING CONFIGURATION +# +# The `keepconf` (disabled by default) keyword can be used to prevent +# xbps from overwriting configuration files. +# +# If set to false, xbps will overwrite configuration files if they +# have not been changed since installation and a newer version is +# available. +# +# If set to true, xbps will save the new configuration file as +# .new- if the original configuration file has not been +# changed since installation. +# keepconf=true + ## VIRTUAL PACKAGES # # Virtual package overrides. You can set your own list of preferred virtual diff --git a/data/xbps.d.5 b/data/xbps.d.5 index f1ab414c..f127a6ee 100644 --- a/data/xbps.d.5 +++ b/data/xbps.d.5 @@ -1,4 +1,4 @@ -.Dd January 18, 2020 +.Dd February 05, 2020 .Dt XBPS-D 5 .Sh NAME .Nm xbps.d @@ -84,6 +84,15 @@ Absolute path to a file and file globbing are supported, example: .It Sy preserve=/usr/bin/foo .It Sy preserve=/etc/foo/*.conf .El +.It Sy keepconf=true|false +If set to false (default), xbps will overwrite configuration files if +they have not been changed since installation and a newer version is +available. +.Pp +If set to true, xbps will save the new configuration file as +.new- if the original configuration file has not been +changed since installation. +.Pp .It Sy repository=url Declares a package repository. The .Ar url diff --git a/include/xbps.h.in b/include/xbps.h.in index 241f7385..00dfa502 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -232,6 +232,14 @@ */ #define XBPS_FLAG_INSTALL_REPRO 0x00008000 +/** + * @def XBPS_FLAG_KEEP_CONFIG + * Don't overwrite configuration files that have not changed since + * installation. + * Must be set through the xbps_handle::flags member. + */ +#define XBPS_FLAG_KEEP_CONFIG 0x00010000 + /** * @def XBPS_FETCH_CACHECONN * Default (global) limit of cached connections used in libfetch. diff --git a/lib/conf.c b/lib/conf.c index 8825afa2..982926c1 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -171,6 +171,7 @@ enum { KEY_ROOTDIR, KEY_SYSLOG, KEY_VIRTUALPKG, + KEY_KEEPCONF, }; static const struct key { @@ -189,6 +190,7 @@ static const struct key { { "rootdir", 7, KEY_ROOTDIR }, { "syslog", 6, KEY_SYSLOG }, { "virtualpkg", 10, KEY_VIRTUALPKG }, + { "keepconf", 8, KEY_KEEPCONF }, }; static int @@ -356,6 +358,15 @@ parse_file(struct xbps_handle *xhp, const char *path, bool nested) case KEY_PRESERVE: store_preserved_file(xhp, val); break; + case KEY_KEEPCONF: + if (strcasecmp(val, "true") == 0) { + xhp->flags |= XBPS_FLAG_KEEP_CONFIG; + xbps_dbg_printf(xhp, "%s: config preservation enabled\n", path); + } else { + xhp->flags &= ~XBPS_FLAG_KEEP_CONFIG; + xbps_dbg_printf(xhp, "%s: config preservation disabled\n", path); + } + break; case KEY_BESTMATCHING: if (strcasecmp(val, "true") == 0) { xhp->flags |= XBPS_FLAG_BESTMATCH; diff --git a/lib/initend.c b/lib/initend.c index acba0c1c..fc053423 100644 --- a/lib/initend.c +++ b/lib/initend.c @@ -181,6 +181,7 @@ xbps_init(struct xbps_handle *xhp) xbps_dbg_printf(xhp, "sysconfdir=%s\n", xhp->sysconfdir); xbps_dbg_printf(xhp, "syslog=%s\n", xhp->flags & XBPS_FLAG_DISABLE_SYSLOG ? "false" : "true"); xbps_dbg_printf(xhp, "bestmatching=%s\n", xhp->flags & XBPS_FLAG_BESTMATCH ? "true" : "false"); + xbps_dbg_printf(xhp, "keepconf=%s\n", xhp->flags & XBPS_FLAG_KEEP_CONFIG ? "true" : "false"); xbps_dbg_printf(xhp, "Architecture: %s\n", xhp->native_arch); xbps_dbg_printf(xhp, "Target Architecture: %s\n", xhp->target_arch); diff --git a/lib/package_config_files.c b/lib/package_config_files.c index 04f03144..d0d7bf33 100644 --- a/lib/package_config_files.c +++ b/lib/package_config_files.c @@ -170,11 +170,13 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, /* * Orig = X, Curr = X, New = Y * - * Install new file (installed file hasn't been modified). + * Install new file (installed file hasn't been modified) if + * configuration option keepconfig is NOT set. */ } else if ((strcmp(sha256_orig, sha256_cur) == 0) && (strcmp(sha256_orig, sha256_new)) && - (strcmp(sha256_cur, sha256_new))) { + (strcmp(sha256_cur, sha256_new)) && + (!(xhp->flags & XBPS_FLAG_KEEP_CONFIG))) { xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Updating configuration file `%s' provided " @@ -212,12 +214,15 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, break; /* * Orig = X, Curr = Y, New = Z + * or + * Orig = X, Curr = X, New = Y if keepconf is set * * Install new file as .new- */ - } else if ((strcmp(sha256_orig, sha256_cur)) && + } else if (((strcmp(sha256_orig, sha256_cur)) && (strcmp(sha256_cur, sha256_new)) && - (strcmp(sha256_orig, sha256_new))) { + (strcmp(sha256_orig, sha256_new))) || + (xhp->flags & XBPS_FLAG_KEEP_CONFIG)) { version = xbps_pkg_version(pkgver); assert(version); snprintf(buf, sizeof(buf), ".%s.new-%s", cffile, version); diff --git a/tests/xbps/libxbps/shell/conf_files_test.sh b/tests/xbps/libxbps/shell/conf_files_test.sh old mode 100644 new mode 100755 index 117dabb4..8f10a86a --- a/tests/xbps/libxbps/shell/conf_files_test.sh +++ b/tests/xbps/libxbps/shell/conf_files_test.sh @@ -225,10 +225,72 @@ tc5_body() { atf_check_equal $rval 0 } +# 6th test: unmodified configuration file on disk, keepconf=true, modified on upgrade. +# result: install new file as ".new-". +atf_test_case tc6 + +tc6_head() { + atf_set "descr" "Tests for configuration file handling: on-disk unmodified, keepconf=true, upgrade modified" +} + +tc6_body() { + mkdir repo + cd repo + mkdir pkg_a + echo "fooblah" > pkg_a/cf1.conf + chmod 644 pkg_a/cf1.conf + xbps-create -A noarch -n a-0.1_1 -s "pkg a" --config-files "/cf1.conf" pkg_a + atf_check_equal $? 0 + rm -rf pkg_a + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + cd .. + + mkdir -p rootdir/xbps.d + echo "keepconf=true" > rootdir/xbps.d/keepconf.conf + + xbps-install -C xbps.d -r rootdir --repository=$PWD/repo -yvd a + atf_check_equal $? 0 + + cd repo + mkdir pkg_a + echo "bazbar" > pkg_a/cf1.conf + chmod 644 pkg_a/cf1.conf + xbps-create -A noarch -n a-0.2_1 -s "pkg a" --config-files "/cf1.conf" pkg_a + atf_check_equal $? 0 + xbps-rindex -d -a $PWD/*.xbps + rm -rf pkg_a + atf_check_equal $? 0 + cd .. + + xbps-install -C xbps.d -r rootdir --repository=$PWD/repo -yuvd + atf_check_equal $? 0 + result="$(cat rootdir/cf1.conf)" + rval=1 + if [ "${result}" = "fooblah" ]; then + rval=0 + fi + echo "file: cf1.conf" + echo "result: ${result}" + echo "expected: fooblah" + atf_check_equal $rval 0 + + result="$(cat rootdir/cf1.conf.new-0.2_1)" + rval=1 + if [ "${result}" = "bazbar" ]; then + rval=0 + fi + echo "file: cf1.conf.new-0.2_1" + echo "result: ${result}" + echo "expected: bazbar" + atf_check_equal $rval 0 +} + atf_init_test_cases() { atf_add_test_case tc1 atf_add_test_case tc2 atf_add_test_case tc3 atf_add_test_case tc4 atf_add_test_case tc5 + atf_add_test_case tc6 }