NotePublic/Software/System/Linux/Common/Linux_下能不能替换运行中的程序.md

2.0 KiB
Raw Blame History

Linux 下能不能替换运行中的程序

今天被朋友问及“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   
  
int main(int argc, char * argv[])  
{  
    foo(); // An export function by libtest.so.  
    sleep(1000);  
    return 0;  
}foo()