This is an automated email from the git hooks/post-receive script.

guillem pushed a commit to branch master
in repository dpkg.

View the commit online:
https://git.dpkg.org/cgit/dpkg/dpkg.git/commit/?id=26993a362cd805d9b7f15f904c97bc1cece8fa9e

commit 26993a362cd805d9b7f15f904c97bc1cece8fa9e
Author: Guillem Jover <[email protected]>
AuthorDate: Fri Jan 8 00:29:49 2021 +0100

    Support remove-on-upgrade conffile flag via DEBIAN/conffiles
    
    Add support for a new "remove-on-upgrade" flag in DEBIAN/conffiles to
    mark that the package wants to remove a given conffile (without having
    to rely on maintscripts).
    
    The flag is added to the conffile line before the flag and is separated
    from the file by a space. Flags never contain "/" and a leading "/" is
    used to determine whether the line has a flag or not.
    
    Closes: #822462
    Based-on-patch-by: Niels Thykier <[email protected]>
    Signed-off-by: Guillem Jover <[email protected]>
---
 dpkg-deb/build.c                                   | 44 +++++++++++-
 lib/dpkg/dpkg-db.h                                 |  1 +
 lib/dpkg/dump.c                                    |  2 +
 lib/dpkg/fields.c                                  | 10 ++-
 lib/dpkg/fsys.h                                    |  2 +
 man/deb-conffiles.pod                              | 16 +++--
 man/dpkg-maintscript-helper.pod                    |  3 +
 src/archives.c                                     |  6 +-
 src/configure.c                                    | 38 ++++++++++-
 src/help.c                                         |  2 +-
 src/unpack.c                                       | 37 ++++++++--
 t-func/deb-content.at                              | 79 ++++++++++++++++++++++
 tests/Makefile                                     |  1 +
 tests/t-conffile-declarative-removal/Makefile      | 49 ++++++++++++++
 .../pkg-conffile-removal-present/DEBIAN/conffiles  |  1 +
 .../pkg-conffile-removal-present}/DEBIAN/control   |  4 +-
 .../test-dir/test-conffile-to-be-removed           |  0
 .../pkg-conffile-v1/DEBIAN/conffiles               |  1 +
 .../pkg-conffile-v1}/DEBIAN/control                |  4 +-
 .../test-dir/test-conffile-to-be-removed           |  0
 .../pkg-conffile-v2/DEBIAN/conffiles               |  1 +
 .../pkg-conffile-v2}/DEBIAN/control                |  4 +-
 22 files changed, 284 insertions(+), 21 deletions(-)

diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c
index 31cd77379..f3ccbf296 100644
--- a/dpkg-deb/build.c
+++ b/dpkg-deb/build.c
@@ -272,6 +272,7 @@ check_conffiles(const char *ctrldir, const char *rootdir)
     struct stat controlstab;
     char *conffilename = conffilenamebuf;
     int n;
+    bool remove_on_upgrade = false;
 
     n = strlen(conffilename);
     if (!n)
@@ -283,8 +284,41 @@ check_conffiles(const char *ctrldir, const char *rootdir)
 
     conffilename[n - 1] = '\0';
 
-    if (conffilename[0] != '/')
-      ohshit(_("conffile name '%s' is not an absolute pathname"), 
conffilename);
+    if (c_isspace(conffilename[0])) {
+      /* The conffiles lines cannot start with whitespace; by handling this
+       * case now, we simplify the remaining code. Move past the whitespace
+       * to give a better error. */
+      while (c_isspace(conffilename[0]))
+        conffilename++;
+      if (conffilename[0] == '\0')
+          ohshit(_("empty and whitespace-only lines are not allowed in "
+                   "conffiles"));
+      ohshit(_("line with conffile filename '%s' has leading white spaces"),
+             conffilename);
+    }
+
+    if (conffilename[0] != '/') {
+      char *flag = conffilename;
+      char *flag_end = strchr(flag, ' ');
+
+      if (flag_end)
+        conffilename = flag_end + 1;
+
+      /* If no flag separator is found, assume a missing leading slash. */
+      if (flag_end == NULL || (conffilename[0] && conffilename[0] != '/'))
+        ohshit(_("conffile name '%s' is not an absolute pathname"), 
conffilename);
+
+      flag_end[0] = '\0';
+
+      /* Otherwise assume a missing filename after the flag separator. */
+      if (conffilename[0] == '\0')
+        ohshit(_("conffile name missing after flag '%s'"), flag);
+
+      if (strcmp(flag, "remove-on-upgrade") == 0)
+        remove_on_upgrade = true;
+      else
+        ohshit(_("unknown flag '%s' for conffile '%s'"), flag, conffilename);
+    }
 
     varbuf_reset(&controlfile);
     varbuf_printf(&controlfile, "%s%s", rootdir, conffilename);
@@ -293,9 +327,13 @@ check_conffiles(const char *ctrldir, const char *rootdir)
         if ((n > 1) && c_isspace(conffilename[n - 2]))
           warning(_("conffile filename '%s' contains trailing white spaces"),
                   conffilename);
-        ohshit(_("conffile '%.250s' does not appear in package"), 
conffilename);
+        if (!remove_on_upgrade)
+          ohshit(_("conffile '%.250s' does not appear in package"), 
conffilename);
       } else
         ohshite(_("conffile '%.250s' is not stattable"), conffilename);
+    } else if (remove_on_upgrade) {
+        ohshit(_("conffile '%s' is present but is requested to be removed"),
+               conffilename);
     } else if (!S_ISREG(controlstab.st_mode)) {
       warning(_("conffile '%s' is not a plain file"), conffilename);
     }
diff --git a/lib/dpkg/dpkg-db.h b/lib/dpkg/dpkg-db.h
index ed0298b9d..cf127c1b0 100644
--- a/lib/dpkg/dpkg-db.h
+++ b/lib/dpkg/dpkg-db.h
@@ -82,6 +82,7 @@ struct conffile {
   const char *name;
   const char *hash;
   bool obsolete;
+  bool remove_on_upgrade;
 };
 
 struct archivedetails {
diff --git a/lib/dpkg/dump.c b/lib/dpkg/dump.c
index 48f0beb03..8fdcf5feb 100644
--- a/lib/dpkg/dump.c
+++ b/lib/dpkg/dump.c
@@ -394,6 +394,8 @@ w_conffiles(struct varbuf *vb,
     varbuf_add_str(vb, i->hash);
     if (i->obsolete)
       varbuf_add_str(vb, " obsolete");
+    if (i->remove_on_upgrade)
+      varbuf_add_str(vb, " remove-on-upgrade");
   }
   if (flags&fw_printheader)
     varbuf_add_char(vb, '\n');
diff --git a/lib/dpkg/fields.c b/lib/dpkg/fields.c
index 977492c70..e540796e4 100644
--- a/lib/dpkg/fields.c
+++ b/lib/dpkg/fields.c
@@ -346,10 +346,11 @@ f_conffiles(struct pkginfo *pkg, struct pkgbin *pkgbin,
             const char *value, const struct fieldinfo *fip)
 {
   static const char obsolete_str[]= "obsolete";
+  static const char remove_on_upgrade_str[] = "remove-on-upgrade";
   struct conffile **lastp, *newlink;
   const char *endent, *endfn, *hashstart;
   int c, namelen, hashlen;
-  bool obsolete;
+  bool obsolete, remove_on_upgrade;
   char *newptr;
 
   lastp = &pkgbin->conffiles;
@@ -364,6 +365,12 @@ f_conffiles(struct pkginfo *pkg, struct pkgbin *pkgbin,
     conffvalue_lastword(value, endent, endent,
                        &hashstart, &hashlen, &endfn,
                         ps);
+    remove_on_upgrade = (hashlen == sizeof(remove_on_upgrade_str) - 1 &&
+                         memcmp(hashstart, remove_on_upgrade_str, hashlen) == 
0);
+    if (remove_on_upgrade)
+      conffvalue_lastword(value, endfn, endent, &hashstart, &hashlen, &endfn,
+                          ps);
+
     obsolete= (hashlen == sizeof(obsolete_str)-1 &&
                memcmp(hashstart, obsolete_str, hashlen) == 0);
     if (obsolete)
@@ -387,6 +394,7 @@ f_conffiles(struct pkginfo *pkg, struct pkgbin *pkgbin,
     newptr[hashlen] = '\0';
     newlink->hash= newptr;
     newlink->obsolete= obsolete;
+    newlink->remove_on_upgrade = remove_on_upgrade;
     newlink->next =NULL;
     *lastp= newlink;
     lastp= &newlink->next;
diff --git a/lib/dpkg/fsys.h b/lib/dpkg/fsys.h
index 8b9107472..748f3a9af 100644
--- a/lib/dpkg/fsys.h
+++ b/lib/dpkg/fsys.h
@@ -77,6 +77,8 @@ enum fsys_namenode_flags {
        FNNF_DEFERRED_RENAME            = DPKG_BIT(8),
        /** Path being filtered. */
        FNNF_FILTERED                   = DPKG_BIT(9),
+       /** Conffile removal requested by upgrade. */
+       FNNF_RM_CONFF_ON_UPGRADE        = DPKG_BIT(10),
 };
 
 /**
diff --git a/man/deb-conffiles.pod b/man/deb-conffiles.pod
index ed87d4431..668af1232 100644
--- a/man/deb-conffiles.pod
+++ b/man/deb-conffiles.pod
@@ -30,19 +30,27 @@ B<DEBIAN/conffiles>
 A package declares its list of conffiles by including a I<conffiles> file
 in its control archive (i.e. I<DEBIAN/conffiles> during package creation).
 
-This file contains a list of files, one per line.
-They should be listed as absolute pathnames, and should exist in the binary
-package, otherwise B<dpkg>(1) will ignore them (although by default
-B<dpkg-deb>(1) will refuse to build such binary packages).
+This file contains a list of files, one per line, with an optional leading
+flag separated by whitespace.
+The conffiles must be listed as absolute pathnames.
 Trailing whitespace will be trimmed, but empty or whitespace-only lines are
 not accepted.
 
+Files without a flag should exist in the binary package, otherwise L<dpkg(1)>
+will ignore them.
+
+There is currently only one flag supported, B<remove-on-upgrade>, to mark
+that a conffile needs to be removed on the next upgrade (since dpkg 1.20.6).
+These files must not exist in the binary package, as both L<dpkg(1)> and
+L<dpkg-deb(1)> will not accept building nor processing such binary packages.
+
 =head1 EXAMPLE
 
  %CONFDIR%/alternatives/README
  %CONFDIR%/cron.daily/dpkg
  %PKGCONFDIR%/dpkg.cfg
  %CONFDIR%/logrotate.d/dpkg
+ remove-on-upgrade /etc/some-old-file.conf
 
 =head1 SEE ALSO
 
diff --git a/man/dpkg-maintscript-helper.pod b/man/dpkg-maintscript-helper.pod
index 4e0e8de45..7e2953a75 100644
--- a/man/dpkg-maintscript-helper.pod
+++ b/man/dpkg-maintscript-helper.pod
@@ -122,6 +122,9 @@ scripts.
 
 =head2 Removing a conffile
 
+Note: This can be replaced in most cases by the C<remove-on-upgrade>
+flag in F<DEBIAN/conffiles> (since dpkg 1.20.6), see L<deb-conffiles(5)>.
+
 If a conffile is completely removed, it should be removed from disk,
 unless the user has modified it. If there are local modifications, they
 should be preserved. If the package upgrades aborts, the newly obsolete
diff --git a/src/archives.c b/src/archives.c
index b20414e3c..96079ab1f 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -235,7 +235,7 @@ md5hash_prev_conffile(struct pkginfo *pkg, char *oldhash, 
const char *oldname,
                              &otherpkg->configversion) != 0)
       continue;
     for (conff = otherpkg->installed.conffiles; conff; conff = conff->next) {
-      if (conff->obsolete)
+      if (conff->obsolete || conff->remove_on_upgrade)
         continue;
       if (strcmp(conff->name, namenode->name) == 0)
         break;
@@ -690,6 +690,10 @@ tarobject(struct tar_archive *tar, struct tar_entry *ti)
 
   namenode = fsys_hash_find_node(ti->name, 0);
 
+  if (namenode->flags & FNNF_RM_CONFF_ON_UPGRADE)
+    ohshit(_("conffile '%s' marked for removal on upgrade, shipped in 
package"),
+           ti->name);
+
   /* Append to list of files.
    * The trailing ‘/’ put on the end of names in tarfiles has already
    * been stripped by tar_extractor(). */
diff --git a/src/configure.c b/src/configure.c
index 12f290451..27f6872a0 100644
--- a/src/configure.c
+++ b/src/configure.c
@@ -356,7 +356,7 @@ deferred_configure_ghost_conffile(struct pkginfo *pkg, 
struct conffile *conff)
 
                for (otherconff = otherpkg->installed.conffiles; otherconff;
                     otherconff = otherconff->next) {
-                       if (otherconff->obsolete)
+                       if (otherconff->obsolete || 
otherconff->remove_on_upgrade)
                                continue;
 
                        /* Check if we need to propagate the new hash from
@@ -401,6 +401,42 @@ deferred_configure_conffile(struct pkginfo *pkg, struct 
conffile *conff)
        cdr2rest = cdr2.buf + strlen(cdr.buf);
        /* From now on we can just strcpy(cdr2rest, extension); */
 
+       if (conff->remove_on_upgrade) {
+               /* Remove DPKGDISTEXT variant if still present. */
+               strcpy(cdr2rest, DPKGDISTEXT);
+               if (unlink(cdr2.buf) < 0 && errno != ENOENT)
+                       warning(_("%s: failed to remove '%.250s': %s"),
+                               pkg_name(pkg, pnaw_nonambig), cdr2.buf,
+                               strerror(errno));
+
+               /* Has it been already removed (e.g. by local admin)? */
+               if (strcmp(currenthash, NONEXISTENTFLAG) == 0)
+                       return;
+
+               /* For unmodified conffiles, we just remove them. */
+               if (strcmp(currenthash, conff->hash) == 0) {
+                       printf(_("Removing obsolete conffile %s ...\n"),
+                              cdr.buf);
+                       if (unlink(cdr.buf) < 0 && errno != ENOENT)
+                               warning(_("%s: failed to remove '%.250s': %s"),
+                                       pkg_name(pkg, pnaw_nonambig), cdr.buf,
+                                       strerror(errno));
+                       return;
+               }
+
+               /* Otherwise, preserve the modified conffile. */
+               strcpy(cdr2rest, DPKGOLDEXT);
+               printf(_("Obsolete conffile '%s' has been modified by you.\n"),
+                      cdr.buf);
+               printf(_("Saving as %s ...\n"), cdr2.buf);
+               if (rename(cdr.buf, cdr2.buf) < 0)
+                       warning(_("%s: cannot rename obsolete conffile '%s' "
+                                 "to '%s': %s"),
+                               pkg_name(pkg, pnaw_nonambig),
+                               cdr.buf, cdr2.buf, strerror(errno));
+               return;
+       }
+
        strcpy(cdr2rest, DPKGNEWEXT);
        /* If the .dpkg-new file is no longer there, ignore this one. */
        if (lstat(cdr2.buf, &stab)) {
diff --git a/src/help.c b/src/help.c
index f8f8a8070..e075ff201 100644
--- a/src/help.c
+++ b/src/help.c
@@ -228,7 +228,7 @@ dir_has_conffiles(struct fsys_namenode *file, struct 
pkginfo *pkg)
         pkg_name(pkg, pnaw_always));
   namelen = strlen(file->name);
   for (conff= pkg->installed.conffiles; conff; conff= conff->next) {
-      if (conff->obsolete)
+      if (conff->obsolete || conff->remove_on_upgrade)
         continue;
       if (strncmp(file->name, conff->name, namelen) == 0 &&
           strlen(conff->name) > namelen && conff->name[namelen] == '/') {
diff --git a/src/unpack.c b/src/unpack.c
index 4da17050f..faf5b2efd 100644
--- a/src/unpack.c
+++ b/src/unpack.c
@@ -344,6 +344,7 @@ deb_parse_conffiles(struct pkginfo *pkg, const char 
*control_conffiles,
     struct conffile *searchconff;
     char *conffilename = conffilenamebuf;
     char *p;
+    enum fsys_namenode_flags confflags = FNNF_NEW_CONFF;
 
     p = conffilename + strlen(conffilename);
     if (p == conffilename)
@@ -355,9 +356,34 @@ deb_parse_conffiles(struct pkginfo *pkg, const char 
*control_conffiles,
     if (p == conffilename)
       continue;
 
-    if (conffilename[0] != '/')
-      ohshit(_("conffile name '%s' is not an absolute pathname"),
-             conffilename);
+    /* Check for conffile flags. */
+    if (conffilename[0] != '/') {
+      char *flag = conffilename;
+      char *flag_end = strchr(flag, ' ');
+
+      if (flag_end)
+        conffilename = flag_end + 1;
+
+      /* If no flag separator is found, assume a missing leading slash. */
+      if (flag_end == NULL || (conffilename[0] && conffilename[0] != '/'))
+        ohshit(_("conffile name '%s' is not an absolute pathname"), 
conffilename);
+
+      flag_end[0] = '\0';
+
+      /* Otherwise assume a missing filename after the flag separator. */
+      if (conffilename[0] == '\0')
+        ohshit(_("conffile name missing after flag '%s'"), flag);
+
+      if (strcmp(flag, "remove-on-upgrade") == 0) {
+        confflags |= FNNF_RM_CONFF_ON_UPGRADE;
+        confflags &= ~FNNF_NEW_CONFF;
+      } else {
+        if (c_isspace(flag[0]))
+          warning(_("line with conffile filename '%s' has leading white 
spaces"),
+                  conffilename);
+        ohshit(_("unknown flag '%s' for conffile '%s'"), flag, conffilename);
+      }
+    }
 
     namenode = fsys_hash_find_node(conffilename, 0);
     namenode->oldhash = NEWCONFFILEFLAG;
@@ -411,7 +437,7 @@ deb_parse_conffiles(struct pkginfo *pkg, const char 
*control_conffiles,
       debug(dbg_conff, "process_archive conffile '%s' no package, no hash",
             newconff->namenode->name);
     }
-    newconff->namenode->flags |= FNNF_NEW_CONFF;
+    newconff->namenode->flags |= confflags;
   }
 
   if (ferror(conff))
@@ -572,6 +598,7 @@ pkg_remove_old_files(struct pkginfo *pkg,
     struct fsys_namenode *usenode;
 
     if ((namenode->flags & FNNF_NEW_CONFF) ||
+        (namenode->flags & FNNF_RM_CONFF_ON_UPGRADE) ||
         (namenode->flags & FNNF_NEW_INARCHIVE))
       continue;
 
@@ -792,6 +819,8 @@ pkg_update_fields(struct pkginfo *pkg, struct 
fsys_namenode_queue *newconffiles)
     newiconff->name = nfstrsave(cfile->namenode->name);
     newiconff->hash = nfstrsave(cfile->namenode->oldhash);
     newiconff->obsolete = !!(cfile->namenode->flags & FNNF_OBS_CONFF);
+    newiconff->remove_on_upgrade = !!(
+        cfile->namenode->flags & FNNF_RM_CONFF_ON_UPGRADE);
     *iconffileslastp = newiconff;
     iconffileslastp = &newiconff->next;
   }
diff --git a/t-func/deb-content.at b/t-func/deb-content.at
index 52fbecc71..e2b7749d6 100644
--- a/t-func/deb-content.at
+++ b/t-func/deb-content.at
@@ -39,6 +39,85 @@ dpkg-deb -b pkg-conff-noabs pkg-conff-noabs.deb
 ], [2], [ignore], [dpkg-deb: error: conffile name 'test-conffile-rel' is not 
an absolute pathname
 ])
 
+DPKG_GEN_CONTROL([pkg-conff-empty])
+printf "   \n" >"pkg-conff-empty/DEBIAN/conffiles"
+AT_CHECK([
+# Conffiles must not contain empty lines.
+dpkg-deb -b pkg-conff-empty pkg-conff-empty.deb
+], [2], [ignore], [dpkg-deb: error: empty and whitespace-only lines are not 
allowed in conffiles
+])
+
+DPKG_GEN_CONTROL([pkg-conff-space-prefix])
+DPKG_GEN_FILE([pkg-conff-space-prefix], [conffiles], [ /test-conffile])
+AT_CHECK([
+# Conffiles must not contain prefixed spaces.
+dpkg-deb -b pkg-conff-space-prefix pkg-conff-space-prefix.deb
+], [2], [ignore], [dpkg-deb: error: line with conffile filename 
'/test-conffile' has leading white spaces
+])
+
+DPKG_GEN_CONTROL([pkg-conff-unknown-flag])
+DPKG_GEN_FILE([pkg-conff-unknown-flag], [conffiles], [unknown-flag 
/test-conffile])
+AT_CHECK([
+# Conffiles marked with an unknown flag.
+dpkg-deb -b pkg-conff-unknown-flag pkg-conff-unknown-flag.deb
+], [2], [ignore], [dpkg-deb: error: unknown flag 'unknown-flag' for conffile 
'/test-conffile'
+])
+
+DPKG_GEN_CONTROL([pkg-conff-missing-pathname])
+printf "unknown-flag \n" >"pkg-conff-missing-pathname/DEBIAN/conffiles"
+AT_CHECK([
+# Conffiles need a pathname, in addition to a flag.
+dpkg-deb -b pkg-conff-missing-pathname pkg-conff-missing-pathname.deb
+], [2], [ignore], [dpkg-deb: error: conffile name missing after flag 
'unknown-flag'
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-missing])
+DPKG_GEN_FILE([pkg-conff-removed-missing], [conffiles], [remove-on-upgrade 
/test-conffile-missing])
+AT_CHECK([
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-missing pkg-conff-removed-missing.deb
+], [0], [ignore], [])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-duped])
+DPKG_GEN_FILE([pkg-conff-removed-duped], [conffiles], [remove-on-upgrade 
/test-conffile-1
+remove-on-upgrade /test-conffile-2
+remove-on-upgrade /test-conffile-1])
+AT_CHECK([
+# Duplicate conffile entries should produce a warning.
+dpkg-deb -b pkg-conff-removed-duped
+], [0], [ignore], [dpkg-deb: warning: conffile name '/test-conffile-1' is 
duplicated
+dpkg-deb: warning: ignoring 1 warning about the control file(s)
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-noeol])
+printf "remove-on-upgrade /test-conffile-1" 
>"pkg-conff-removed-noeol/DEBIAN/conffiles"
+AT_CHECK([
+# Conffiles need a final newline to guarantee there has been no accidental
+# file truncation.
+dpkg-deb -b pkg-conff-removed-noeol pkg-conff-removed-noeol.deb
+], [2], [ignore], [dpkg-deb: error: conffile name 'remove-on-upgrade 
/test-conffile-1' is too long, or missing final newline
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-noabs])
+DPKG_GEN_FILE([pkg-conff-removed-noabs], [conffiles], [remove-on-upgrade 
test-conffile-rel])
+AT_DATA([pkg-conff-removed-noabs/test-conffile-rel], [test init
+])
+AT_CHECK([
+# Conffiles must use absolute pathnames.
+dpkg-deb -b pkg-conff-removed-noabs pkg-conff-removed-noabs.deb
+], [2], [ignore], [dpkg-deb: error: conffile name 'test-conffile-rel' is not 
an absolute pathname
+])
+
+DPKG_GEN_CONTROL([pkg-conff-removed-present])
+DPKG_GEN_FILE([pkg-conff-removed-present], [conffiles], [remove-on-upgrade 
/test-conffile-present])
+AT_DATA([pkg-conff-removed-present/test-conffile-present], [test init
+])
+AT_CHECK([
+# Conffiles marked for removal must not be present.
+dpkg-deb -b pkg-conff-removed-present pkg-conff-removed-present.deb
+], [2], [ignore], [dpkg-deb: error: conffile '/test-conffile-present' is 
present but is requested to be removed
+])
+
 DPKG_GEN_CONTROL([pkg-deb-newline])
 touch 'pkg-deb-newline/file
 newline'
diff --git a/tests/Makefile b/tests/Makefile
index d3aabea18..6a52e50e2 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -90,6 +90,7 @@ TESTS_PASS += t-conffile-replaces-disappear
 TESTS_PASS += t-conffile-replaces-diverted
 TESTS_PASS += t-conffile-versioned-replaces-downgrade
 TESTS_PASS += t-conffile-rename
+TESTS_PASS += t-conffile-declarative-removal
 TESTS_PASS += t-queue-process-deconf-dupe
 TESTS_PASS += t-symlink-dir
 TESTS_PASS += t-switch-symlink-abs-to-dir
diff --git a/tests/t-conffile-declarative-removal/Makefile 
b/tests/t-conffile-declarative-removal/Makefile
new file mode 100644
index 000000000..d6cd06169
--- /dev/null
+++ b/tests/t-conffile-declarative-removal/Makefile
@@ -0,0 +1,49 @@
+TESTS_DEB := pkg-conffile-v1 pkg-conffile-v2
+
+include ../Test.mk
+
+test-case:
+       # Conffile marked for removal but present, cannot be installed.
+       $(DPKG_BUILD_DEB) --nocheck pkg-conffile-removal-present
+       ! $(DPKG_INSTALL) pkg-conffile-removal-present.deb
+       $(call pkg_is_not_installed,pkg-conffile-removal-present)
+       $(DPKG_PURGE) pkg-conffile-removal-present
+
+       # Unmodified case.
+       $(DPKG_INSTALL) pkg-conffile-v1.deb
+       test -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+       $(DPKG_INSTALL) pkg-conffile-v2.deb
+       test ! -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+
+       # Reset.
+       $(DPKG_PURGE) pkg-conffile
+       test ! -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+
+       # Unmodified case; but force it to happen via two invocations.
+       $(DPKG_INSTALL) pkg-conffile-v1.deb
+       test -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+       $(DPKG_UNPACK) pkg-conffile-v2.deb
+       # The old file is still present when unpacked.
+       test -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+       test ! -f 
"$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed.dpkg-old"
+       $(DPKG_CONFIGURE) pkg-conffile
+       # After configure, the file is removed.
+       test ! -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+       test ! -f 
"$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed.dpkg-old"
+
+       # Reset.
+       $(DPKG_PURGE) pkg-conffile
+       test ! -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+
+       # Modified; should store .dpkg-old.
+       $(DPKG_INSTALL) pkg-conffile-v1.deb
+       test -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+       echo "modify this" 
>"$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+       $(DPKG_INSTALL) pkg-conffile-v2.deb
+       test ! -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed"
+       test -f "$(DPKG_INSTDIR)/test-dir/test-conffile-to-be-removed.dpkg-old"
+
+test-clean:
+       $(DPKG_PURGE) pkg-conffile-removal-present
+       $(DPKG_PURGE) pkg-conffile
+       $(BEROOT) $(RM) -rf "$(DPKG_INSTDIR)/test-dir"
diff --git 
a/tests/t-conffile-declarative-removal/pkg-conffile-removal-present/DEBIAN/conffiles
 
b/tests/t-conffile-declarative-removal/pkg-conffile-removal-present/DEBIAN/conffiles
new file mode 100644
index 000000000..587753be1
--- /dev/null
+++ 
b/tests/t-conffile-declarative-removal/pkg-conffile-removal-present/DEBIAN/conffiles
@@ -0,0 +1 @@
+remove-on-upgrade /test-dir/test-conffile-to-be-removed
diff --git a/tests/t-breaks/lib-b-1/DEBIAN/control 
b/tests/t-conffile-declarative-removal/pkg-conffile-removal-present/DEBIAN/control
similarity index 53%
copy from tests/t-breaks/lib-b-1/DEBIAN/control
copy to 
tests/t-conffile-declarative-removal/pkg-conffile-removal-present/DEBIAN/control
index 7c423caca..78d5ee4a3 100644
--- a/tests/t-breaks/lib-b-1/DEBIAN/control
+++ 
b/tests/t-conffile-declarative-removal/pkg-conffile-removal-present/DEBIAN/control
@@ -1,7 +1,7 @@
-Package: lib-b
+Package: pkg-conffile-removal-present
 Version: 1
 Section: test
 Priority: extra
 Maintainer: Dpkg Developers <[email protected]>
 Architecture: all
-Description: test package - broken package
+Description: test package - conffile to be removed but present
diff --git a/scripts/t/Dpkg_Checksums/empty 
b/tests/t-conffile-declarative-removal/pkg-conffile-removal-present/test-dir/test-conffile-to-be-removed
similarity index 100%
copy from scripts/t/Dpkg_Checksums/empty
copy to 
tests/t-conffile-declarative-removal/pkg-conffile-removal-present/test-dir/test-conffile-to-be-removed
diff --git 
a/tests/t-conffile-declarative-removal/pkg-conffile-v1/DEBIAN/conffiles 
b/tests/t-conffile-declarative-removal/pkg-conffile-v1/DEBIAN/conffiles
new file mode 100644
index 000000000..c4138c4fa
--- /dev/null
+++ b/tests/t-conffile-declarative-removal/pkg-conffile-v1/DEBIAN/conffiles
@@ -0,0 +1 @@
+/test-dir/test-conffile-to-be-removed
diff --git a/tests/t-conffile-normal/pkg-conffile/DEBIAN/control 
b/tests/t-conffile-declarative-removal/pkg-conffile-v1/DEBIAN/control
similarity index 66%
copy from tests/t-conffile-normal/pkg-conffile/DEBIAN/control
copy to tests/t-conffile-declarative-removal/pkg-conffile-v1/DEBIAN/control
index 6dcdeb8ab..5626d2a32 100644
--- a/tests/t-conffile-normal/pkg-conffile/DEBIAN/control
+++ b/tests/t-conffile-declarative-removal/pkg-conffile-v1/DEBIAN/control
@@ -1,7 +1,7 @@
 Package: pkg-conffile
-Version: 0
+Version: 1
 Section: test
 Priority: extra
 Maintainer: Dpkg Developers <[email protected]>
 Architecture: all
-Description: test package - conffile inside directory
+Description: test package - conffile to be removed v1
diff --git a/scripts/t/Dpkg_Checksums/empty 
b/tests/t-conffile-declarative-removal/pkg-conffile-v1/test-dir/test-conffile-to-be-removed
similarity index 100%
copy from scripts/t/Dpkg_Checksums/empty
copy to 
tests/t-conffile-declarative-removal/pkg-conffile-v1/test-dir/test-conffile-to-be-removed
diff --git 
a/tests/t-conffile-declarative-removal/pkg-conffile-v2/DEBIAN/conffiles 
b/tests/t-conffile-declarative-removal/pkg-conffile-v2/DEBIAN/conffiles
new file mode 100644
index 000000000..587753be1
--- /dev/null
+++ b/tests/t-conffile-declarative-removal/pkg-conffile-v2/DEBIAN/conffiles
@@ -0,0 +1 @@
+remove-on-upgrade /test-dir/test-conffile-to-be-removed
diff --git a/tests/t-conffile-normal/pkg-conffile/DEBIAN/control 
b/tests/t-conffile-declarative-removal/pkg-conffile-v2/DEBIAN/control
similarity index 66%
copy from tests/t-conffile-normal/pkg-conffile/DEBIAN/control
copy to tests/t-conffile-declarative-removal/pkg-conffile-v2/DEBIAN/control
index 6dcdeb8ab..70574322e 100644
--- a/tests/t-conffile-normal/pkg-conffile/DEBIAN/control
+++ b/tests/t-conffile-declarative-removal/pkg-conffile-v2/DEBIAN/control
@@ -1,7 +1,7 @@
 Package: pkg-conffile
-Version: 0
+Version: 2
 Section: test
 Priority: extra
 Maintainer: Dpkg Developers <[email protected]>
 Architecture: all
-Description: test package - conffile inside directory
+Description: test package - conffile to be removed v2

-- 
Dpkg.Org's dpkg

Reply via email to