今天被朋友问及“Linux下可以替换运行中的程序么?”,以前依稀记得Linux下是可以的(而Windows就不让),于是随口答道“OK”。结果朋友发来一个执行结果:(test正在运行中)
# cp test2 test cp: cannot create regular file `test': Text file busy

看起来是程序被占用,无法覆盖。于是自己又再做了几个实验:

(1)先rm删除正在运行的test,然后cp test2 test就没有错误了。
(2)先mv改名正在运行的test,然后cp test2 test也没有问题。

查了查资料并动手分析了一下,找到了比较满意的解释。cp并不改变目标文件的inode,事实上它的实现是这样的:
# strace cp test2 test  2>&1 | grep open.*test open("test2", O_RDONLY|O_LARGEFILE)     = 3 open("test", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4

我原以为cp的实现是“rm + open(O_CREAT)”,不过现在想想上面的实现方式才是最可靠的(保证了时序安全和目标文件的属性)。这也可以解释为什么cp的目标文件会继承被覆盖文件的属性而非源文件。

Linux由于Demand Paging机制的关系,必须确保正在运行中的程序镜像(注意,并非文件本身)不被意外修改,因此内核在启动程序后会锁定这个程序镜像的inode。这就是为什么cp在用“O_WRONLY|O_TRUNC”模式open目标文件时会失败。而先rm再cp的话,新文件的inode其实已经改变了,原 inode并没有被真正删除,直到内核释放对它的引用。同理,mv只是改变了文件名,其inode不变,新文件使用了新的inode。

问题到这里已经水落石出,不过刨根究底的个性驱使我再做了以下一组实验,没想到结果完全出乎我意料之外!

写了一个简单的测试程序:
#include <stdio.h> int main(int argc, char * argv[]) { foo();  // An export function by libtest.so. sleep(1000); return 0; }

foo()是另一个测试动态库libtest.so的导出接口,只打印一行提示就返回。接下来我把上面对执行文件的测试用例对动态库又做了一遍:

(1)cp libtest2.so libtest.so可以直接覆盖已加载的动态库。
(2)先rm删除已加载的libtest.so,然后cp libtest2.so libtest.so成功。
(3)先mv改名已加载的libtest.so,然后cp libtest2.so libtest.so成功。

除了第一个用例外,结果相同。这样看来,动态库被加载时难道ld并没有锁定inode?不过想想也可以宽恕,毕竟ld也是用户态程序,没有权利去锁定inode,也不应与内核的文件系统底层实现耦合。

到这里都还算在情理之中,看起来Linux也都处理的很好。不过还剩下一个问题:动态库被以cp的方式覆盖后难道不会和Demand Paging机制产生冲突?

在思考这个问题的过程中,我意识到前面这个测试程序的一个致命漏洞,稍作修改如下:
#include <stdio.h> int main(int argc, char * argv[]) { loop: foo();  // An export function by libtest.so. sleep(1); goto loop; return 0; }

这次,再执行上面的三个用例后发现,“cp libtest2.so libtest.so”虽然仍可直接覆盖已加载的动态库,但是测试程序马上出现了“Segmentation fault”。而后两个用例结果不变。由此可见,想要安全的替换已加载的动态库,还是用“笨拙”的“rm + cp”吧,看似捷径的“cp覆盖”会直接葬送掉你的程序……

看来,我再一次低估了Linux的健壮性,看似符合逻辑的流程也可能会带来灾难性的后果;“rm & cp”与“cp覆盖”背后所隐藏的底层差异却可以成为你的救星。Linux用得越久越是让人觉得这是一块充满了荆棘和陷阱的原始丛林,只有步步为营实踏前行才能走的更远。

注:以上实验基于SuSE Linux Enterprise Server 9 SP1(Linux 2.6.5 & glibc 2.3.3)。

[转载] linux 程序运行过程中替换文件的更多相关文章

  1. (转)在.NET程序运行过程中,什么是堆,什么是栈?什么情况下会在堆(栈)上分配数据?它们有性能上的区别吗?“结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?

    转自:http://www.cnblogs.com/xiaoyao2011/archive/2011/09/09/2172427.html 在.NET程序运行过程中,什么是堆,什么是栈? 堆也就是托管 ...

  2. 程序运行过程中遇到“ORA-03114: not connected to ORACLE”的问题解决

    c#,winform程序,数据批量入oracle库时用到DataAdaper的.FillSchema函数,如:da.FillSchema(dt2, SchemaType.Mapped); 程序运行一段 ...

  3. Java 程序运行过程中的内存分析

    作为 java 程序员,都应该知道 Java 程序运行在 JVM(Java Virtual Machine,Java 虚拟机)上,可以把 JVM 理解成 Java 程序和操作系统之间的桥梁,JVM 实 ...

  4. 放在NSArray、NSDictionary等容器内的对象Item,Item中的property在程序运行过程中被无故释放

    可能是被释放的property本身是OC对象而它的属性被误写成assign,例如: @interface MyItem : Object @property (nonatomic, assign) N ...

  5. robot framework程序运行过程中,遇到点击事件之后,未出现点击之后的效果(求解)

    1.click Element操作,在实际过程中偶然会出现,日志显示已点击成功,但是实际自动化页面,没有点击成功之后的操作 现象: 现象描述:程序执行到点击侧边栏的[人员信息]之后,日志显示已经点击成 ...

  6. STM32在程序运行过程中关闭定时器重新打开后定时器不工作的问题

    问题:数码管显示程序放在定时TIM2中断函数里面扫描,想要实现在关闭某一功能的时候数码管不显示. 刚开始的想法是开关关闭,关闭定时器时钟:开关打开,打开定时器时钟:(但实验证明再次打开开关时定时器2却 ...

  7. Java内存管理-程序运行过程(一)

    勿在流沙住高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 相信在做Java开发的伙伴一定知道 JVM(Java Virtual Machine( ...

  8. opencv检错:程序运行过程正常,当跳出函数时出现断言错误(Debug Assertion Failed)

    转载http://blog.csdn.net/u012327581/article/details/51351780 1.问题描述 在VS2015下配置好Opencv后,程序在函数运行过程中正常,调试 ...

  9. java 程序运行过程 简介

    这里的Java程序运行过程,是指我们编译好代码之后,在命令行开始执行java xxx命令,到java程序开始执行起来的这一过程,我们称其为运行时. 第一步,操作系统解析我们输入的java xxx命令, ...

随机推荐

  1. php中替换函数主要用的几个函数strtr(),str_repalce()。

    php中替换函数主要有strtr(),str_repalce()这两个函数,今天介绍下他们的区别和用法, 先来看看这个php字符串替换函数 strtr()的两种用法: strtr(string,fro ...

  2. MongoDB Shell

    MongoDB Shell   1.连接指定主机及数据库 mongo 127.0.0.1:30000/myDB 链接到127.0.0.1的30000端口的myDB 2.启动后连接指定数据库 *.&qu ...

  3. C#Web编程

    1.Web服务器控件可以包含服务器上调用的事件处理程序.只有送回服务器时,才在服务器上触发事件.把autoPostBack设置为true,事件将立即传给服务器.这样就会使客户端调用Javascript ...

  4. 天大acm 题号1002 Maya Calendar

    Description 上周末,M.A. Ya教授对古老的玛雅有了一个重大发现.从一个古老的节绳(玛雅人用于记事的工具)中,教授发现玛雅人使用了一个一年有365天的叫做Haab的历法.这 个Haab历 ...

  5. 在ubuntu上搭建turnserver

    这边文章的目的:搭建turnserver,设定开机启动 1.下载turnserver的源码,最新的地址https://code.google.com/p/rfc5766-turn-server/ no ...

  6. html移动开发app-framework2.0使用心得

    1.页面切换动画结束时卡(禁用动画) 2.搜索或导航标签需要固定(标签选择器动态修改高度) 3.pancel容器默认生成的时候内容不放 通过动态的的$("").empty().ht ...

  7. YTU 2335: 0-1背包问题

    2335: 0-1背包问题 时间限制: 1 Sec  内存限制: 128 MB 提交: 15  解决: 12 题目描述 试设计一个用回溯法搜索子集空间树的函数.该函数的参数包括结点可行性判定函数和上界 ...

  8. WPF中viewmodel层怎样得到view层的TabControl控件对象?

    View层: <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns: ...

  9. Paths on a Grid(简单组合数学)

    Paths on a Grid Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 23008 Accepted: 5683 Desc ...

  10. Inviting Friends(二分+背包)

    Inviting Friends Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...