Search code examples
linuxdebiandpkg

dpkg remove + install works, upgrade fails and leaves inconsistent state. How to debug?


I'm running in Debian11. I have built a .deb package which installs a service and runs correctly. File foo_bar.deb, package name foobar, executable name foo_bar

When I install with dpkg dpkg -i foo_bar.deb and then run dpkg -l I see the status is ii, good

I can then remove it dpkg -r foobar, which makes the status rc. If I then purge dpkg --purge foobar, it disappears from the list, as expected

But if when it is already installed I try to install an update, or the same or downgrade it with dpkg -i foo_bar-2.deb, the upgrade fails and leaves it in an inconsistent state forcing me to dpkg --purge --force-all foobar. The error says

dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
Terminated

What is different between upgrading and manually removing + installing the new version? How can I figure out what is wrong with my package?

I tried to increase the debug output of dpkg in the failed upgrade and I got the following, which I cannot manage to understand:

$ sudo dpkg -i -D133 foo_bar-1.1-70271f3_amd64.deb
D000001: ensure_diversions: new, (re)loading
D000001: ensure_statoverrides: new, (re)loading
D000010: path_remove_tree '/var/lib/dpkg/tmp.ci'
(Reading database ... 306080 files and directories currently installed.)
Preparing to unpack foo-1.1-70271f3_amd64.deb ...
D000001: process_archive oldversionstatus=installed
D000002: fork/exec /var/lib/dpkg/info/foobar.prerm ( upgrade 1.1-70271f3 )
Foo stopping...
WARNING: Foo will restart automatically after 1 second
D000001: ensure_diversions: same, skipping
D000002: fork/exec /var/lib/dpkg/tmp.ci/preinst ( upgrade 1.1-70271f3 1.1-70271f3 )
Foo stopping...
WARNING: Foo will restart automatically after 1 second
D000001: ensure_diversions: same, skipping
Unpacking foo (1.1-70271f3) over (1.1-70271f3) ...
D000010: tarobject ti->name='.' mode=40755 owner=0:0 type=53(d) ti->linkname='' namenode='/.' flags=2 instead='<none>'
D000100: setupvnamevbs main='/.' tmp='/..dpkg-tmp' new='/..dpkg-new'
D000100: tarobject already exists
D000100: tarobject directory exists
D000010: tarobject ti->name='./etc' mode=40755 owner=0:0 type=53(d) ti->linkname='' namenode='/etc' flags=2 instead='<none>'
D000100: setupvnamevbs main='/etc' tmp='/etc.dpkg-tmp' new='/etc.dpkg-new'
D000100: tarobject already exists
D000100: tarobject directory exists
D000010: tarobject ti->name='./etc/init.d' mode=40755 owner=0:0 type=53(d) ti->linkname='' namenode='/etc/init.d' flags=2 instead='<none>'
D000100: setupvnamevbs main='/etc/init.d' tmp='/etc/init.d.dpkg-tmp' new='/etc/init.d.dpkg-new'
D000100: tarobject already exists
D000100: tarobject directory exists
D000010: tarobject ti->name='./etc/init.d/foobar' mode=100755 owner=0:0 type=48(-) ti->linkname='' namenode='/etc/init.d/foobar' flags=2 instead='<none>'
D000100: setupvnamevbs main='/etc/init.d/foobar' tmp='/etc/init.d/foobar.dpkg-tmp' new='/etc/init.d/foobar.dpkg-new'
D000100: tarobject already exists
D000010: path_remove_tree '/etc/init.d/foobar.dpkg-new'
D000010: path_remove_tree '/etc/init.d/foobar.dpkg-tmp'
D000100: tarobject file open size=1268
D000100: tarobject file hash=b4f54378713678119b467ef5792c9a01
D000100: tarobject nondirectory, 'link' backup
D000100: tarobject done and installation deferred
D000010: tarobject ti->name='./etc/systemd' mode=40755 owner=0:0 type=53(d) ti->linkname='' namenode='/etc/systemd' flags=2 instead='<none>'
D000100: setupvnamevbs main='/etc/systemd' tmp='/etc/systemd.dpkg-tmp' new='/etc/systemd.dpkg-new'
D000100: tarobject already exists
D000100: tarobject directory exists
D000010: tarobject ti->name='./etc/systemd/system' mode=40755 owner=0:0 type=53(d) ti->linkname='' namenode='/etc/systemd/system' flags=2 instead='<none>'
D000100: setupvnamevbs main='/etc/systemd/system' tmp='/etc/systemd/system.dpkg-tmp' new='/etc/systemd/system.dpkg-new'
D000100: tarobject already exists
D000100: tarobject directory exists
D000010: tarobject ti->name='./etc/systemd/system/foobar.service' mode=100644 owner=0:0 type=48(-) ti->linkname='' namenode='/etc/systemd/system/foobar.service' flags=2 instead='<none>'
D000100: setupvnamevbs main='/etc/systemd/system/foo.service' tmp='/etc/systemd/system/foobar.service.dpkg-tmp' new='/etc/systemd/system/foo.service.dpkg-new'
D000100: tarobject already exists
D000010: path_remove_tree '/etc/systemd/system/foobar.service.dpkg-new'
D000010: path_remove_tree '/etc/systemd/system/foobar.service.dpkg-tmp'
D000100: tarobject file open size=200
D000100: tarobject file hash=fcd2172a70d64205d0ec211ac55e0a0d
D000100: tarobject nondirectory, 'link' backup
D000100: tarobject done and installation deferred
D000010: tarobject ti->name='./usr' mode=40755 owner=0:0 type=53(d) ti->linkname='' namenode='/usr' flags=2 instead='<none>'
D000100: setupvnamevbs main='/usr' tmp='/usr.dpkg-tmp' new='/usr.dpkg-new'
D000100: tarobject already exists
D000100: tarobject directory exists
D000010: tarobject ti->name='./usr/bin' mode=40755 owner=0:0 type=53(d) ti->linkname='' namenode='/usr/bin' flags=2 instead='<none>'
D000100: setupvnamevbs main='/usr/bin' tmp='/usr/bin.dpkg-tmp' new='/usr/bin.dpkg-new'
D000100: tarobject already exists
D000100: tarobject directory exists
D000010: tarobject ti->name='./usr/bin/foo_bar' mode=100755 owner=0:0 type=48(-) ti->linkname='' namenode='/usr/bin/foo_bar' flags=2 instead='<none>'
D000100: setupvnamevbs main='/usr/bin/foo_bar' tmp='/usr/bin/foo_bar.dpkg-tmp' new='/usr/bin/foo_bar.dpkg-new'
D000100: tarobject already exists
D000010: path_remove_tree '/usr/bin/foo_bar.dpkg-new'
D000010: path_remove_tree '/usr/bin/foo_bar.dpkg-tmp'
D000100: tarobject file open size=833496
dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
Terminated

I also tried to simply install + remove + install, that goes without a hitch. It causes problems only with install + install


Solution

  • The reason why it went wrong was due to my choice for names in the package, service, and executable.

    My prerm file called my /etc/init.d/foobar file with the argument stop, which in turn would run ps -ef | grep foo_bar | grep -v grep | awk '{print $2}' | xargs kill & > /dev/null, with the intention of killing the executable foo_bar running in the background. As a side effect it also killed any process including the string foo_bar, e.g.: dpkg -i foo_bar.deb. Killing the install process during the install is bad.

    On the other hand, when removing the package with dpkg -r foobar, the name did not include foo_bar so it was not killed and the removal went well.

    Lesson: Do NOT name your executable the same as your package, or at least kill your processes in a smarter way