英文:
dpkg remove + install works, upgrade fails and leaves inconsistent state. How to debug?
问题
我正在Debian11上运行。我已经构建了一个.deb包,该包安装了一个服务并运行正常。文件 foo_bar.deb
,包名称 foobar
,可执行文件名称 foo_bar
。
当我使用dpkg安装它 dpkg -i foo_bar.deb
然后运行 dpkg -l
,我看到状态是 ii
,很好。
然后我可以删除它 dpkg -r foobar
,这将使状态变为 rc
。如果我然后执行清除操作 dpkg --purge foobar
,它会从列表中消失,如预期。
但是,如果当它已安装时,我尝试使用 dpkg -i foo_bar-2.deb
安装更新,或者相同版本或降级版本,升级将失败并使其处于不一致状态,迫使我执行 dpkg --purge --force-all foobar
。错误消息如下:
dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
Terminated
升级和手动删除+安装新版本之间有什么不同?我如何找出我的软件包出了什么问题?
我尝试增加失败升级的dpkg的调试输出,我得到了以下结果,我无法理解:
$ 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
<details>
<summary>英文:</summary>
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
</details>
# 答案1
**得分**: 0
由于我在包、服务和可执行文件的命名选择上出了问题,导致它出现了问题。
我的 `prerm` 文件调用了我的 `/etc/init.d/foobar` 文件,并使用参数 `stop`,然后会运行 `ps -ef | grep foo_bar | grep -v grep | awk '{print $2}' | xargs kill & > /dev/null`,意图是杀死后台运行的可执行文件 `foo_bar`。作为副作用,它还会杀死包括字符串 `foo_bar` 的任何进程,例如:`dpkg -i foo_bar.deb`。在安装过程中杀死安装进程是不好的。
另一方面,使用 `dpkg -r foobar` 删除包时,名称不包括 `foo_bar`,因此它不会被杀死,卸载顺利进行。
**教训:不要将可执行文件的名称与包的名称相同,或者至少以更智能的方式终止您的进程。**
<details>
<summary>英文:</summary>
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**
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论