apt如何升级正在运行的程序?

som*_*ega 29 apt

我想知道apt upgrade如何升级正在运行的程序。

它会等到程序终止吗?

它是否只是在程序运行时覆盖文件?这不会干扰正在运行的程序吗?

那么共享库呢?

mat*_*ick 46

在 POSIX(Linux 是 POSIX 系统)中,至少在使用 POSIX 文件系统时,允许文件在被删除后保持打开状态(即,在取消链接后,通过从特定文件名中删除链接到底层的 inode 对象,它实际上将特定的字节串标识为文件的内容)。处于这种状态的文件仍然可以被具有打开句柄的代码访问(用户域中的文件描述符,内核域中的其他结构),尽管它们不再具有名称1和任何试图打开旧的name 将无法再获取它们。这意味着,如果您执行以下操作:

$ cat /tmp/foo.txt # step 1
foo
$ rm /tmp/foo.txt # step 2
$ echo "bar" > /tmp/foo.txt # step 3
Run Code Online (Sandbox Code Playgroud)

您实际上并没有更改 的内容/tmp/foo.txt,而是创建了一个新的、不相关的和独立的文件,该文件可以以相同的名称访问,而旧文件不再是。

此外,POSIX 还提供原子重命名,其中文件立即重命名为现有名称,并在没有中间状态的情况下替换原始文件。从本质上讲,它是一种机制,可以保证在上面的第 2 步和第 3 步之间没有任何内容可以看到旧文件已删除但新文件尚未到位。

apt升级一个正在运行的二进制文件时,它实际上并没有改变文件的内容;相反,它使用原子重命名立即将新的(并且完全独立的,如上所述)文件从临时名称移动到旧文件的位置。打开旧文件的任何内容(包括将其作为可执行文件运行的进程)都将继续查看和使用旧内容,就好像什么都没发生过一样。但是当进程终止并重新启动时,将按名称查找其代码,因此将使用新内容。这也意味着可以让进程执行相同命名的二进制文件,但运行不同的代码。

但是请注意,以上仅适用于单个文件。如果应用程序的所有资源分布在多个文件中,则没有什么可以原子替换它们的资源,因此,例如,如果二进制文件动态加载共享库,或者在启动后按名称打开一些数据,它很可能看到出乎意料的东西和故障和/或崩溃。这就是为什么您会收到弹出窗口,告诉您在升级后重新启动 Firefox,“否则您会遇到问题”。

1准确地说,它们不再具有那个特定的名称,因为允许以多个名称访问文件(即 inode)。然而,绝大多数文件只有一个名称,当它们与名称不同时,一旦没有打开它们,它们就会被删除2

2这种延迟删除也是为什么在某些情况下您可能会删除文件以回收磁盘空间,却发现没有空间被释放。那是因为某些东西打开了这些文件,并将它们保持在僵尸、无名但还活着的状态。

  • _“文件被删除后可以打开”_ - 我知道你的意思,但这听起来不对。也许将其更改为“文件被删除后允许保持打开状态”之类的内容? (12认同)
  • @marcelm 从技术上讲,您可以通过打开`/proc/$pid/fd/` 下的魔术链接,在删除文件(但仍由进程打开)后打开文件 (5认同)
  • @marcelm 或“文件在删除后允许*保持*打开”。 (2认同)
  • @Parto:不过,我不明白为什么它应该是一项社会实验。 (2认同)

Pil*_*ot6 13

apt upgrade覆盖文件。它不会影响正在运行的程序,因为它们已加载到 RAM 中。如果您重新启动程序,则会启动一个新版本。

在升级某些软件包时,如果需要,可能会运行某些触发器或脚本来重新启动某些服务。

  • @Nyos“留在磁盘上/在 RAM 中” - 在磁盘上。这在删除保持打开的大(日志)文件时尤其明显,以查看 `df` 仍然显示未释放的磁盘空间,而 `ls` 不再列出文件。 (3认同)
  • @Pilot6 我不同意问“如果发生什么事”太宽泛了。这就是这个答案实际上没有解决的问题的重点。 (3认同)
  • @somega:已打开的文件 - 删除时 - 保留在磁盘/RAM 中,直到它们关闭。但是,运行过时的程序无法打开已删除的文件。 (2认同)

Pau*_*per 3

它会等到程序终止吗?

也许吧,具体取决于包裹。

它会在程序运行时简单地覆盖文件吗?这不会影响程序的运行吗?

可以,具体取决于程序和文件。

那么共享库呢?

这取决于它是否已经加载到内存中。/sf/answers/543718171/


完整答案

Apt(实际上是底层的 dpkg)在卸载和安装软件包时运行脚本。如果软件包包含长时间运行的程序(守护程序),则通常会在删除旧版本软件包时停止它,并在安装新版本软件包时启动它。

preinst 该脚本在从其 Debian 存档(“.deb”)文件中解压其所属包之前执行。许多“preinst”脚本会停止正在升级的软件包的服务,直到安装或升级完成(在“postinst”脚本成功执行之后)。

postinst 一旦 foo 从 Debian 存档(“.deb”)文件中解压出来,此脚本通常会完成 foo 包所需的任何配置。通常,“postinst”脚本会要求用户输入,和/或警告他们,如果他们接受默认值,他们应该记得返回并根据需要重新配置该包。一旦安装或升级了新软件包,许多“postinst”脚本就会执行启动或重新启动服务所需的任何命令。

prerm 此脚本通常会停止与包关联的任何守护程序。它在删除与包关联的文件之前执行。

postrm 此脚本通常会修改与 foo 关联的链接或其他文件,和/或删除由包创建的文件。(另请参阅什么是虚拟包?第 7.8 节。)

https://www.debian.org/doc/manuals/debian-faq/ch-pkg_basics.en.html

当然,由包维护者来启动和停止 postinst 和 prerm 中的服务。