Linux 如何升级正在使用的软件包?

nuh*_*aga 3 arch-linux package-management

我正在使用 Arch Linux,例如,我可以在网上冲浪时进行系统升级。如果程序本身在使用,如何升级浏览器包?还是以内核为例?是否不需要停止可执行文件以替换为新的可执行文件?还是会在下次重新启动时发生?

Ant*_*hon 8

光盘上的浏览器文件刚刚被替换。正在运行的程序(如果不是完全在内存中)保持旧的可执行文件打开,直到程序关闭(但在此之前那些不再是您通过目录条目获得的可执行文件)。下次重新启动浏览器时,您将获得版本。

除了在重新启动时加载的程序(即内核)之外,不需要重新启动 有一些程序可以为内核打补丁,甚至不需要为此重新启动,但这不是一回事。

  • @Xen2050 没有文件被“替换”这样的事情。删除目录条目,不触及文件数据,并创建一个新文件,目录条目指向新文件。旧文件还在。 (4认同)
  • @Xen2050 - 试试这个:`{ rm /tmp/"$$".tmp; echo nope 仍然在这里>&3; ls -l /tmp/"$$".tmp /dev/fd/3; 读取 var <&3; 回声“$var”;} 3<>/tmp/"$$".tmp` - 内核的文件系统,真正的*文件系统,跟踪每个正在运行的进程打开的文件,并在 VFS 中维护这些描述符。由于它们未链接,它们可能不再拥有磁盘空间的所有权,但只要有读取器/写入器对它们拥有所有权,它们就仍然存在*某处。* (3认同)

Mar*_*ick 7

正如您所怀疑的那样,类 Unix 系统可以防止大多数正在执行的文件被覆盖。以下是标准关于开放系统调用的说明:

如果出现以下情况,open() 函数可能会失败:

[ETXTBSY] 该文件是正在执行的纯过程(共享文本)文件,oflag 为 O_WRONLY 或 O_RDWR。

但是正在执行的文件仍然可以取消链接,这就是包管理器的工作方式。

以下是dpkgDebian 和 Ubuntu 在安装/bin/cpio刚刚发布的新版本时所做的事情:

open("/bin/cpio.dpkg-new", O_WRONLY|O_CREAT|O_EXCL, 0) = 10
// lots of reads and writes omitted from this listing.
// It's copying the new version into dpkg-new
fchown(10, 0, 0)                  = 0 
fchmod(10, 0755)                  = 0 
close(10)                         = 0 
rename("/bin/cpio.dpkg-new", "/bin/cpio") = 0 
Run Code Online (Sandbox Code Playgroud)

详细来说,这个:

  • 将新版本复制到cpio.dpkg-newcpio.
  • 将所有者和文件权限设置为包所说的任何内容
  • 重命名cpio.dpkg-newcpio

安全地安装文件的新版本而不会处于文件不存在的位置(即使是瞬间)的方法是使用重命名系统调用。这要求两个文件都在同一个文件系统中,这就是 dpkg 在与旧版本相同的目录中创建新版本 cpio 的原因。标准说:

int rename(const char *old, const char *new);

rename() 函数将更改文件的名称。旧参数指向要重命名的文件的路径名。新参数指向文件的新路径名。

如果新参数命名的链接存在,则应将其删除并将旧的重命名为新的。在这种情况下,在整个重命名操作期间,名为 new 的链接应该对其他进程保持可见,并在操作开始之前引用 new 或 old 引用的文件。

术语可能有点混乱,因为这里给出的文件和文件rename分别是 cpio新版本和 cpio旧版本

最后,这是回答您问题的关键:

如果新参数命名的链接存在并且文件的链接计数在删除时变为 0 且没有进程打开该文件,则该文件占用的空间将被释放并且该文件将不再可访问。如果一个或多个进程在删除最后一个链接时打开了文件,则应在 rename() 返回之前删除该链接,但应推迟文件内容的删除,直到对文件的所有引用都关闭。

最后一句意味着如果任何进程cpiorename完成时打开(或正在运行它),它们将继续查看文件的先前内容,直到关闭文件(或退出)。

Archpacman似乎做了大致相同的事情:

snprintf(checkfile, len, "%s.paccheck", filename);
...
if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) {
    errors++;
    goto needbackup_cleanup;
}
...
if(try_rename(handle, checkfile, filename)) {
    errors++;
}
Run Code Online (Sandbox Code Playgroud)

尽管包管理器努力安全地安装新文件,但在使用过程中更新程序时可能会出现一些问题。例如,firefox 包有十多个可执行文件和共享对象。在更新期间运行旧版本 Firefox 的人可能会发现,他们在更新完成后调用的扩展程序与旧版本的 Firefox 不兼容。我最近在 Ubuntu 上更新了 firefox,并且 apt-get 打印出来:

请重新启动所有正在运行的 Firefox 实例,否则您会遇到问题。

如果您是多用户系统的系统管理员,最好向用户社区宣布待定更新。