#182747 dpkg should not remove a symlink to a directory unless it's empty

Package:
dpkg
Source:
dpkg
Description:
Debian package management system
Submitter:
Marco d'Itri
Date:
2015-02-25 11:09:14 UTC
Severity:
wishlist
#182747#5
Date:
2003-02-27 17:22:46 UTC
From:
To:
<Md> doogie: do you remember my problem with dpkg killing the news spool?
<doogie> md: vaguely
<Md> doogie: well... the problem was just that /var/spool/news was a symlink to      another directory, so dpkg could removed it
<doogie> md: oh, then admin error
<doogie> md: of course, I don't really see a sane way to work around that.
<Md> doogie: I agree that there is no good fix, but I would not define it
     "admin error" either
<doogie> md: file a wishlist bug, with these details
<doogie> md: maybe when dpkg gets a file database that contains meta info,
         something could be done

Explanation: old inn2 package contained directories below
/var/spool/news/. After installing it, /var/spool/news/ was moved and
a symlink was placed there.
Then I installed a new inn2 package, which did not contain
/var/spool/news/. Unexpectedly, the symlink was deleted even if it
pointed to a non-empty directory.

#182747#10
Date:
2006-07-01 17:01:14 UTC
From:
To:
If I understand correctly, you want /var/spool/news to exist always,
not conditional on any package being installed.  Isn't the solution to
this just to create the symlink in the maintscripts, and *not* include
it in the package?

Justin

#182747#15
Date:
2006-07-01 17:15:19 UTC
From:
To:
I needed a symlink because of local issues.
#182747#18
Date:
2006-07-01 17:15:19 UTC
From:
To:
I needed a symlink because of local issues.
#182747#23
Date:
2006-07-02 19:53:32 UTC
From:
To:
Oh, okay.  So you wanted to avoid dpkg removing a local
file/modification (since it has a different type)?  Isn't this what
local diversions are for?

  dpkg-divert --rename /var/spool/news && ln -s .. /var/spool/news

#182747#28
Date:
2006-07-02 20:09:42 UTC
From:
To:
No, because the original /var/spool/news was a directory and directories
cannot be diverted.
My point is that before removing a directory dpkg should check that it
actually still is a directory and not a symlink to a non-empty directory.

#182747#39
Date:
2009-04-07 01:26:31 UTC
From:
To:
I've created a package for a proprietary software that bundles with java.  We've decided since then to replace the bundled java with a symlink to the system java, but when our systems update the package, they are left with an empty directory.  I have attached some small test packages that exhibit this problem if you do an update, but not if you do a removal and install.
#182747#44
Date:
2009-04-16 17:41:55 UTC
From:
To:
This is normal and unrelated to the bug 182747. If you want to replace a
directory by a symlink you have to do that in the maintainer scripts on
upgrade. Same for replacing a symlink with a directory. That's because
dpkg tries to preserve admin changes between symlinks and directories
(Debian policy document this).

Cheers,

#182747#53
Date:
2009-06-17 19:35:44 UTC
From:
To:
Hello,

I've just found this bug and I must say is a real pain for vendors
which package stuff which installs in /opt.

I also found an easy way to reproduce the bug. See the bottom of this
message for details.


As a test one of the guys at work made /opt a symlink and we observed
that, although other directories were present in /opt, after the
removal of any of the
packages that has files in /opt, the symlink is gone somewhere right
after or during prerm.

I edited the maintainer scripts and added this snippet at the
beginning of each one:

echo ' >>> $0 : $1 : $2 : $3 '
ls -l -d /opt || echo '/opt is missing'

This the trimmed listing:


twix:/tmp# aptitude purge foo
...
 >>> /var/lib/dpkg/info/foo.prerm : remove :  :
lrwxrwxrwx 1 root root 9 2009-06-17 20:05 /opt -> opt-real/
...
 >>> /var/lib/dpkg/info/foo.postrm : remove :  :
ls: cannot access /opt: No such file or directory
/opt is missing
Curăț fișierele de configurare pentru foo ...
 >>> /var/lib/dpkg/info/foo.postrm : purge :  :
ls: cannot access /opt: No such file or directory
/opt is missing
Se procesează declanșatorii pentru man-db ...
...




As a demo I created a modified hello package whose intefdiff is:

0 eddy@twix ~/usr/src/perso/symlinkopt $ interdiff -z hello_2.2-3{,.1}.diff.gz
diff -u hello-2.2/debian/changelog hello-2.2/debian/changelog
--- hello-2.2/debian/changelog
+++ hello-2.2/debian/changelog
@@ -1,3 +1,10 @@
+hello (2.2-3.1) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * put some file in /opt to test a possible bug in dpkg
+
+ -- Eddy Petrișor <eddy.petrisor@gmail.com>  Wed, 17 Jun 2009 21:36:53 +0300
+
 hello (2.2-3) unstable; urgency=low

   * Added debian/watch file. Closes: #489213.
diff -u hello-2.2/debian/rules hello-2.2/debian/rules
--- hello-2.2/debian/rules
+++ hello-2.2/debian/rules
@@ -48,6 +48,9 @@
 	cp -a NEWS debian/copyright $(docdir)
 	cp -a debian/changelog $(docdir)/changelog.Debian
 	cp -a ChangeLog $(docdir)/changelog
+	# put stuff in /opt
+	mkdir -p debian/tmp/opt/hello/share/doc
+	cp -a NEWS debian/copyright debian/tmp/opt/hello/share/doc
 	cd $(docdir) && gzip -9 changelog changelog.Debian
 	gzip -r9 debian/tmp/usr/share/man
 	dpkg-shlibdeps debian/tmp/usr/bin/hello



Steps to reproduce:
1. mv /opt /opt-real && ln -s /opt-real /opt
2. mkdir -p /opt-real/bar && echo 'non-empty' > /opt-real/bar/bar-ish
3. install the attached hello deb (or build one from the attached source package
4. dpkg --remove hello

Result:
/opt symlink was deleted

Expected result:
/opt symlink should have been left as it was since there was also bar in there