在Linux中替换正在运行的可执行文件

33

我有一个嵌入式 Linux 系统,可以从 USB 卡更新自身。界面程序检测到 USB 插入并查找升级后的可执行文件。我目前将其复制到本地文件,并在 rc5.d 中安装一些命令以在下次启动时将文件复制到现有 exe 上。然后我让软件重新启动。

有更好的方法吗?


使用install程序而不是cp。请参考https://unix.stackexchange.com/a/95932/162125。 - undefined
3个回答

40

你不需要让它在下次启动时复制文件,相反,这个步骤可以正常运作:

  • 将新的可执行文件复制到本地文件。
  • 验证本地文件。
  • unlink()现有的可执行文件。
  • 将新的可执行文件重命名为正确的名称。

应用程序会在 unlink() 后继续运行 - 直到所有正在执行的副本完成后,内核才会释放底层数据。

然后,您甚至可以只使用execve()将当前正在运行的进程替换为新上传的版本。


36

程序正在运行中,只要首先使用rm (unlink) 命令删除可执行文件,就可以替换它了。

不要用 cp 替换文件,因为那样做会导致问题。要么使用 mv 命令移动文件,或者更确保的方法是先使用 rm 删除文件,然后将新文件放到同一位置。如果您正在对嵌入式软件中的代码进行操作,则应该从 unlink(2) 命令开始。

Unix内核知道inode仍在使用中,他们会删除文件的目录条目,但他们不会释放inode(和数据块),直到inode引用计数归零,而当实例正在运行时,这种情况不会发生。

这在您的嵌入式系统中可能不是问题,但作为一般警告,请勿指望这适用于网络存储,除非在服务器本身上。


2
我想我也应该补充一下,如果网络是在文件系统层以下完成的话,那么你就没问题了;因此,这种技术在 iSCSI 中是可以的。 - DigitalRoss
看起来在原地重新构建可执行文件是不被允许的,除非你先使用 rm 命令删除可执行文件。否则,链接器将把新的可执行文件写入相同的 inode 中,你正在运行的进程可能会崩溃...就像我的一样。 - Mark Lakata

13

在Linux中,当进程正在运行时,您可以安全地替换正在运行的可执行文件。只要进程正在运行,那个实例将继续使用“旧”的代码。所有对该应用程序的新调用都将使用“新”的代码。因此,简单地重新启动应用程序(或必要时重新启动设备)将使用新的副本。

请注意,如果您的应用程序将更改配置文件或库,则必须小心,因为它们可能不在内存中。在这种情况下,更安全的方法是让脚本执行您所提到的操作。


3
需要强调的关键点是,为了确保这一保证成立,您需要先使用unlink()函数(例如使用rm命令)删除原始文件。 - j_random_hacker
1
替换必须通过先使用rm删除现有文件或将现有文件移动到新名称来完成。简单地“替换”文件是不安全的。 - Mark Lakata

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接