summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavlina Moravcova Varekova <pmoravco@redhat.com>2017-04-19 18:16:18 +0200
committerPavlina Moravcova Varekova <pmoravco@redhat.com>2017-04-19 18:16:18 +0200
commitb9178e43c355e1b60280937737d96a50f7597c1e (patch)
treebeca606fee93cba1ae92e60d2a9b324885211a49
parenta239ddefa90575ce80ed4436beb4005a97e32644 (diff)
downloadrpm-pavlinas_p122.tar.gz
Add %mutable and %noupdate update policies (#152)pavlinas_p122
%mutable - is defined for files and links. It means update until modified. In more details: - if a file/link is the same as in new package then touch it, - if a file/link is the same as in old package then upgrade it as "normal" file/link, - else do nothing. %noupdate - is defined for all file types used internally by rpm. It is for cases, where packager wants just the initial content, never to be touched by rpm again. In more details: - if the file does not exist, then create it, - if the file exists, then do nothing.
-rw-r--r--build/files.c4
-rw-r--r--lib/rpmfi.c136
-rw-r--r--lib/rpmfi_internal.h25
-rw-r--r--lib/rpmfiles.h2
-rw-r--r--lib/transaction.c15
-rw-r--r--tests/data/SPECS/updpolicy.spec38
-rw-r--r--tests/rpmi.at254
7 files changed, 473 insertions, 1 deletions
diff --git a/build/files.c b/build/files.c
index f58569e3e..f0bd242ef 100644
--- a/build/files.c
+++ b/build/files.c
@@ -836,6 +836,10 @@ static VFA_t const virtualAttrs[] = {
{ "%license", RPMFILE_LICENSE },
{ "%pubkey", RPMFILE_PUBKEY },
{ "%missingok", RPMFILE_MISSINGOK },
+ { "%mutable", RPMFILE_MUTABLE },
+ { "%noupdate", RPMFILE_NOUPDATE },
+ { "%updatepolicy(mutable)", RPMFILE_MUTABLE },
+ { "%updatepolicy(noupdate)", RPMFILE_NOUPDATE },
{ NULL, 0 }
};
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
index 320296a4d..93970ea05 100644
--- a/lib/rpmfi.c
+++ b/lib/rpmfi.c
@@ -1089,6 +1089,142 @@ exit:
return action;
}
+
+rpmFileAction rpmfilesSetMutableAction(rpmfiles ofi, int oix,
+ rpmfiles nfi, int nix)
+{
+ char * fn = rpmfilesFN(nfi, nix);
+ rpmFileTypes diskWhat;
+ struct stat sb;
+ int action = FA_UNKNOWN;
+
+ /* The file doesn't exist on the disk. Create it. */
+ if (lstat(fn, &sb)) {
+ action = FA_CREATE;
+ goto exit;
+ }
+
+ diskWhat = rpmfiWhatis((rpm_mode_t)sb.st_mode);
+
+ if ((diskWhat == REG) &&
+ (rpmfiWhatis(rpmfilesFMode(ofi, oix)) == REG) &&
+ (rpmfiWhatis(rpmfilesFMode(nfi, nix)) == REG) ) {
+ char buffer[1024];
+ int oalgo, nalgo;
+ size_t odiglen, ndiglen;
+ const unsigned char * odigest, * ndigest;
+ const char * nfuser, * ofuser;
+ uid_t uid;
+ const char * nfgroup, * ofgroup;
+ gid_t gid;
+
+ /* If the file on disk is identical to the one in new pkg, then touch it */
+ if (rpmfilesFSize(nfi, nix) == sb.st_size) {
+
+ if (rpmfilesFMode(nfi, nix) == ((rpm_mode_t)sb.st_mode)) {
+
+ nfuser = rpmfilesFUser(nfi, nix);
+ if ((nfuser && rpmugUid(nfuser, &uid) == 0) &&
+ (uid == sb.st_uid)) {
+
+ nfgroup = rpmfilesFGroup(nfi, nix);
+ if ((nfgroup && rpmugGid(nfgroup, &gid) == 0) &&
+ (gid == sb.st_gid)) {
+
+ ndigest = rpmfilesFDigest(nfi, nix, &nalgo, &ndiglen);
+ if ((!rpmDoDigest(nalgo, fn, 0, (unsigned char *)buffer, NULL)) &&
+ (ndigest && memcmp(ndigest, buffer, ndiglen) == 0)) {
+ action = FA_TOUCH;
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+
+ /* If the file on disk is identical to the one in old pkg, then create it */
+ if (rpmfilesFSize(ofi, oix) == sb.st_size) {
+
+ if (rpmfilesFMode(ofi, oix) == ((rpm_mode_t)sb.st_mode)) {
+
+ ofuser = rpmfilesFUser(ofi, oix);
+ if ((ofuser && rpmugUid(ofuser, &uid) == 0) &&
+ (uid == sb.st_uid)) {
+
+ ofgroup = rpmfilesFGroup(ofi, oix);
+ if ((ofgroup && rpmugGid(ofgroup, &gid) == 0) &&
+ (gid == sb.st_gid)) {
+
+ odigest = rpmfilesFDigest(ofi, oix, &oalgo, &odiglen);
+ if ((!rpmDoDigest(oalgo, fn, 0, (unsigned char *)buffer, NULL)) &&
+ (odigest && memcmp(odigest, buffer, odiglen) == 0)) {
+ action = FA_CREATE;
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+
+ /* file is changed, let it be */
+ action = FA_SKIP;
+
+ } else if ((diskWhat == LINK) &&
+ (rpmfiWhatis(rpmfilesFMode(ofi, oix)) == LINK) &&
+ (rpmfiWhatis(rpmfilesFMode(nfi, nix)) == LINK) ) {
+
+ char buffer[1024];
+ const char * oFLink, * nFLink;
+
+ /* if the link on disk is identical to the one in new pkg, then touch it */
+ nFLink = rpmfilesFLink(nfi, nix);
+
+ ssize_t link_len = readlink(fn, buffer, sizeof(buffer) - 1);
+ if (link_len != -1) {
+ buffer[link_len] = '\0';
+ if (nFLink && rstreq(nFLink, buffer)) {
+ action = FA_TOUCH;
+ goto exit;
+ }
+ }
+
+ /* if the link on disk is identical to the one in old pkg, then create it */
+ oFLink = rpmfilesFLink(ofi, oix);
+ if ((link_len != -1) && (oFLink && rstreq(oFLink, buffer))) {
+ action = FA_CREATE;
+ goto exit;
+ }
+
+ /* link is changed, let it be */
+ action = FA_SKIP;
+ }
+
+exit:
+ free(fn);
+ return action;
+ }
+
+
+rpmFileAction rpmfilesSetNoupdateAction(rpmfiles ofi, int oix,
+ rpmfiles nfi, int nix)
+{
+ char * fn = rpmfilesFN(nfi, nix);
+ struct stat sb;
+ int action = FA_UNKNOWN;
+
+ if (lstat(fn, &sb)) {
+ /* The file/link/ doesn't exist on the disk. Create it. */
+ action = FA_CREATE;
+ } else {
+ /* The file exists, let it be. */
+ action = FA_SKIP;
+ }
+
+ free(fn);
+ return action;
+ }
+
+
int rpmfilesConfigConflict(rpmfiles fi, int ix)
{
char * fn = NULL;
diff --git a/lib/rpmfi_internal.h b/lib/rpmfi_internal.h
index cb3284c0f..804333f2d 100644
--- a/lib/rpmfi_internal.h
+++ b/lib/rpmfi_internal.h
@@ -73,6 +73,31 @@ rpmFileAction rpmfilesDecideFate(rpmfiles ofi, int oix,
rpmfiles nfi, int nix,
int skipMissing);
+
+/** \ingroup rpmfi
+ * Return action which should be done with the %mutable file
+ * @param new file info set
+ * @param new file index
+ * @param old file info set
+ * @param old file index
+ * @return action name
+ */
+RPM_GNUC_INTERNAL
+rpmFileAction rpmfilesSetMutableAction(rpmfiles ofi, int oix,
+ rpmfiles nfi, int nix);
+
+/** \ingroup rpmfi
+ * Return action which should be done with the %noupdate file
+ * @param new file info set
+ * @param new file index
+ * @param old file info set
+ * @param old file index
+ * @return action name
+ */
+RPM_GNUC_INTERNAL
+rpmFileAction rpmfilesSetNoupdateAction(rpmfiles ofi, int oix,
+ rpmfiles nfi, int nix);
+
RPM_GNUC_INTERNAL
int rpmfilesConfigConflict(rpmfiles fi, int ix);
diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
index 4dba88fc4..8e92d0c4f 100644
--- a/lib/rpmfiles.h
+++ b/lib/rpmfiles.h
@@ -60,6 +60,8 @@ enum rpmfileAttrs_e {
RPMFILE_README = (1 << 8), /*!< from %%readme */
/* bits 9-10 unused */
RPMFILE_PUBKEY = (1 << 11), /*!< from %%pubkey */
+ RPMFILE_MUTABLE = (1 << 12), /*!< from %%mutable or %updatepolicy(mutable) */
+ RPMFILE_NOUPDATE = (1 << 13), /*!< from %%noupdate or %updatepolicy(noupdate) */
};
typedef rpmFlags rpmfileAttrs;
diff --git a/lib/transaction.c b/lib/transaction.c
index d8cd1e6e9..e7efe65c2 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -414,6 +414,7 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfiles fi, int fx
{
rpmfs fs = rpmteGetFileStates(p);
int isCfgFile = ((rpmfilesFFlags(otherFi, ofx) | rpmfilesFFlags(fi, fx)) & RPMFILE_CONFIG);
+ rpmFileAction action;
if (XFA_SKIPPING(rpmfsGetAction(fs, fx)))
return;
@@ -471,10 +472,22 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfiles fi, int fx
/* Determine config file disposition, skipping missing files (if any). */
if (isCfgFile) {
int skipMissing = ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1);
- rpmFileAction action;
action = rpmfilesDecideFate(otherFi, ofx, fi, fx, skipMissing);
rpmfsSetAction(fs, fx, action);
+
+ } else {
+ if (rpmfilesFFlags(fi, fx) & RPMFILE_MUTABLE) {
+ action = rpmfilesSetMutableAction(otherFi, ofx, fi, fx);
+ rpmfsSetAction(fs, fx, action);
+
+ } else {
+ if (rpmfilesFFlags(fi, fx) & RPMFILE_NOUPDATE) {
+ action = rpmfilesSetNoupdateAction(otherFi, ofx, fi, fx);
+ rpmfsSetAction(fs, fx, action);
+ }
+ }
}
+
rpmfilesSetFReplacedSize(fi, fx, rpmfilesFSize(otherFi, ofx));
}
diff --git a/tests/data/SPECS/updpolicy.spec b/tests/data/SPECS/updpolicy.spec
new file mode 100644
index 000000000..4310e8c23
--- /dev/null
+++ b/tests/data/SPECS/updpolicy.spec
@@ -0,0 +1,38 @@
+# avoid depending on rpm configuration
+%define _sysconfdir /etc
+
+%{!?filetype: %global filetype file}
+
+Name: update-policy-test%{?sub:-%{sub}}
+Version: %{ver}
+Release: 1
+Summary: Testing update policy
+
+Group: Testing
+License: GPL
+BuildArch: noarch
+
+%description
+%{summary}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}
+case %{filetype} in
+file)
+ echo "%{filedata}" > $RPM_BUILD_ROOT/%{_sysconfdir}/policy.conf
+ ;;
+link)
+ ln -s "%{filedata}" $RPM_BUILD_ROOT/%{_sysconfdir}/policy.conf
+ ;;
+dir)
+ mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/policy.conf
+ ;;
+esac
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root,-)
+%{?fileattr} %{_sysconfdir}/policy.conf
diff --git a/tests/rpmi.at b/tests/rpmi.at
index 2fd7d5b5d..8bfa0ab4c 100644
--- a/tests/rpmi.at
+++ b/tests/rpmi.at
@@ -354,3 +354,257 @@ runroot rpm -e testdoc
[],
[])
AT_CLEANUP
+
+
+# ------------------------------
+# Test mutable file
+AT_SETUP([mutable file - only works as root!])
+AT_KEYWORDS([mutable policy link])
+AT_CHECK([
+AT_XFAIL_IF([test `whoami` != root ])
+RPMDB_CLEAR
+RPMDB_INIT
+cf="${RPMTEST}"/etc/policy.conf
+rm -rf "${cf}" "${cf}".rpm*
+rm -rf "${TOPDIR}"
+
+for v in 1.0 2.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype file" \
+ --define "filedata old_contents" \
+ --define "fileattr %mutable" \
+ /data/SPECS/updpolicy.spec
+done
+
+for v in 3.0 4.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype file" \
+ --define "filedata new_contents" \
+ --define "fileattr %mutable" \
+ /data/SPECS/updpolicy.spec
+done
+
+
+#test update mutable file without changes and with changed contents
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-1.0-1.noarch.rpm
+cat "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-2.0-1.noarch.rpm
+cat "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-3.0-1.noarch.rpm
+cat "${cf}"
+echo "CHANGE" > "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-4.0-1.noarch.rpm
+cat "${cf}"
+
+runroot rpm -e update-policy-test
+test ! -f "${cf}" && echo OK1
+
+
+#test update mutable file with changed mode
+runroot rpm -U /build/RPMS/noarch/update-policy-test-2.0-1.noarch.rpm
+cat "${cf}"
+chmod a+x "${cf}"
+runroot rpm -U /build/RPMS/noarch/update-policy-test-3.0-1.noarch.rpm
+cat "${cf}"
+runroot rpm -e update-policy-test
+test ! -f "${cf}" && echo OK2
+],
+[],
+[old_contents
+old_contents
+new_contents
+CHANGE
+OK1
+old_contents
+old_contents
+OK2
+],
+[])
+AT_CLEANUP
+
+
+# ------------------------------
+# Test mutable link
+AT_SETUP([mutable link])
+AT_KEYWORDS([mutable policy link])
+AT_CHECK([
+RPMDB_CLEAR
+RPMDB_INIT
+cf="${RPMTEST}"/etc/policy.conf
+rm -rf "${cf}" "${cf}".rpm*
+rm -rf "${TOPDIR}"
+
+for v in 1.0 2.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype link" \
+ --define "filedata old_contents" \
+ --define "fileattr %mutable" \
+ /data/SPECS/updpolicy.spec
+done
+
+for v in 3.0 4.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype link" \
+ --define "filedata new_contents" \
+ --define "fileattr %mutable" \
+ /data/SPECS/updpolicy.spec
+done
+
+
+#test update mutable link without changes and with changed contents
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-1.0-1.noarch.rpm
+readlink "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-2.0-1.noarch.rpm
+readlink "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-3.0-1.noarch.rpm
+readlink "${cf}"
+ln -sf "CHANGE" "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-4.0-1.noarch.rpm
+readlink "${cf}"
+
+runroot rpm -e update-policy-test
+test ! -L "${cf}" && echo OK1
+],
+[],
+[old_contents
+old_contents
+new_contents
+CHANGE
+OK1
+],
+[])
+AT_CLEANUP
+
+
+
+
+
+# ------------------------------
+# Test noupdate file
+AT_SETUP([noupdate file])
+AT_KEYWORDS([noupdate policy link])
+AT_CHECK([
+RPMDB_CLEAR
+RPMDB_INIT
+cf="${RPMTEST}"/etc/policy.conf
+rm -rf "${cf}" "${cf}".rpm*
+rm -rf "${TOPDIR}"
+
+for v in 1.0 2.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype file" \
+ --define "filedata old_contents" \
+ --define "fileattr %noupdate" \
+ /data/SPECS/updpolicy.spec
+done
+
+for v in 3.0 4.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype file" \
+ --define "filedata new_contents" \
+ --define "fileattr %noupdate" \
+ /data/SPECS/updpolicy.spec
+done
+
+
+#test update mutable file without changes and with changed contents
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-1.0-1.noarch.rpm
+cat "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-2.0-1.noarch.rpm
+cat "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-3.0-1.noarch.rpm
+cat "${cf}"
+echo "CHANGE" > "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-4.0-1.noarch.rpm
+cat "${cf}"
+
+runroot rpm -e update-policy-test
+test ! -f "${cf}" && echo OK1
+
+],
+[],
+[old_contents
+old_contents
+old_contents
+CHANGE
+OK1
+],
+[])
+AT_CLEANUP
+
+
+# ------------------------------
+# Test noupdate link
+AT_SETUP([noupdate link])
+AT_KEYWORDS([noupdate policy link])
+AT_CHECK([
+RPMDB_CLEAR
+RPMDB_INIT
+cf="${RPMTEST}"/etc/policy.conf
+rm -rf "${cf}" "${cf}".rpm*
+rm -rf "${TOPDIR}"
+
+for v in 1.0 2.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype link" \
+ --define "filedata old_contents" \
+ --define "fileattr %noupdate" \
+ /data/SPECS/updpolicy.spec
+done
+
+for v in 3.0 4.0; do
+ runroot rpmbuild --quiet -bb \
+ --define "ver ${v}" \
+ --define "filetype link" \
+ --define "filedata new_contents" \
+ --define "fileattr %noupdate" \
+ /data/SPECS/updpolicy.spec
+done
+
+
+#test update mutable link without changes and with changed contents
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-1.0-1.noarch.rpm
+readlink "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-2.0-1.noarch.rpm
+readlink "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-3.0-1.noarch.rpm
+readlink "${cf}"
+ln -sf "CHANGE" "${cf}"
+
+runroot rpm -U /build/RPMS/noarch/update-policy-test-4.0-1.noarch.rpm
+readlink "${cf}"
+
+runroot rpm -e update-policy-test
+test ! -L "${cf}" && echo OK1
+],
+[],
+[old_contents
+old_contents
+old_contents
+CHANGE
+OK1
+],
+[])
+AT_CLEANUP