nuh*_*aga 3 arch-linux package-management
我正在使用 Arch Linux,例如,我可以在网上冲浪时进行系统升级。如果程序本身在使用,如何升级浏览器包?还是以内核为例?是否不需要停止可执行文件以替换为新的可执行文件?还是会在下次重新启动时发生?
光盘上的浏览器文件刚刚被替换。正在运行的程序(如果不是完全在内存中)保持旧的可执行文件打开,直到程序关闭(但在此之前那些不再是您通过目录条目获得的可执行文件)。下次重新启动浏览器时,您将获得版本。
除了在重新启动时加载的程序(即内核)之外,不需要重新启动 有一些程序可以为内核打补丁,甚至不需要为此重新启动,但这不是一回事。
正如您所怀疑的那样,类 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-new与cpio.cpio.dpkg-new为cpio安全地安装文件的新版本而不会处于文件不存在的位置(即使是瞬间)的方法是使用重命名系统调用。这要求两个文件都在同一个文件系统中,这就是 dpkg 在与旧版本相同的目录中创建新版本 cpio 的原因。标准说:
int rename(const char *old, const char *new);
rename() 函数将更改文件的名称。旧参数指向要重命名的文件的路径名。新参数指向文件的新路径名。
如果新参数命名的链接存在,则应将其删除并将旧的重命名为新的。在这种情况下,在整个重命名操作期间,名为 new 的链接应该对其他进程保持可见,并在操作开始之前引用 new 或 old 引用的文件。
术语可能有点混乱,因为这里给出的旧文件和新文件rename分别是 cpio的新版本和 cpio的旧版本。
最后,这是回答您问题的关键:
如果新参数命名的链接存在并且文件的链接计数在删除时变为 0 且没有进程打开该文件,则该文件占用的空间将被释放并且该文件将不再可访问。如果一个或多个进程在删除最后一个链接时打开了文件,则应在 rename() 返回之前删除该链接,但应推迟文件内容的删除,直到对文件的所有引用都关闭。
最后一句意味着如果任何进程cpio在rename完成时打开(或正在运行它),它们将继续查看文件的先前内容,直到关闭文件(或退出)。
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 实例,否则您会遇到问题。
如果您是多用户系统的系统管理员,最好向用户社区宣布待定更新。