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

41 lines
2.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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()
```