# Linux 下能不能替换运行中的程序 今天被朋友问及“Linux 下可以替换运行中的程序么?”,以前依稀记得 Linux 下是可以的(而 Windows 就不让),于是随口答道“OK”。结果朋友发来一个执行结果:(test 正在运行中) ```bash 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,事实上它的实现是这样的: ```cpp # 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。 问题到这里已经水落石出,不过刨根究底的个性驱使我再做了以下一组实验,没想到结果完全出乎我意料之外! 写了一个简单的测试程序: ```cpp #include int main(int argc, char * argv[]) { foo(); // An export function by libtest.so. sleep(1000); return 0; }foo() ```