在这里它说您可以重写可执行文件,并且该进程将正常运行-进程重新启动时将重新读取该文件。
但是,当我尝试在进程运行时替换二进制文件时(使用scp,从开发人员到测试服务器),它说“文件繁忙”。而且,如果我替换了共享库文件(* .so),则链接该文件的所有进程都会崩溃。
为什么这样?我想念什么吗?如何在不停止/不破坏进程的情况下替换二进制文件?
stop app && create symlink of .so && start app
在这里它说您可以重写可执行文件,并且该进程将正常运行-进程重新启动时将重新读取该文件。
但是,当我尝试在进程运行时替换二进制文件时(使用scp,从开发人员到测试服务器),它说“文件繁忙”。而且,如果我替换了共享库文件(* .so),则链接该文件的所有进程都会崩溃。
为什么这样?我想念什么吗?如何在不停止/不破坏进程的情况下替换二进制文件?
stop app && create symlink of .so && start app
Answers:
如为何软件包即使升级也能正常运行?,则将锁放置在inode而不是文件名上。当您加载并执行二进制文件时,该文件被标记为忙-这就是为什么当您尝试写入它时出现ETXTBSY(文件忙)错误的原因。
现在,对于共享库,它稍有不同:使用可以将库映射到进程的地址空间中mmap()
。尽管MAP_DENYWRITE
可以指定,但至少Linux上的Glibc会静默忽略它(根据手册页,请随时检查源代码)-检查此线程。因此,你实际上是在允许写入文件,并且,因为它是存储器映射的,任何变化都可见几乎立即-这意味着如果你足够努力,你可以设法 砖通过覆盖库中的机器。
因此,正确的更新方法是:
删除文件,从文件系统中删除对数据的引用,以使任何可能要使用它的新生成的应用程序都无法访问该文件,同时使已打开(或映射)该文件的任何人都可以访问该数据;
创建具有更新内容的新文件。
新创建的进程将使用更新的内容,正在运行的应用程序将访问旧版本。这是任何理智的软件包管理实用程序的功能。请注意,这并不是完全没有任何危险-例如,dlsym()
如果库的API进行静默更改,则动态加载代码(使用和朋友)的应用程序将遇到麻烦。
如果您真的很安全,请关闭系统,从另一个操作系统实例挂载文件系统,然后进行更新并再次启动已更新的系统。
.so
使用检查文件的ldd filename.so
依赖性来检查文件