linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗

当程序运行的时候,如果把可执行文件删除或者把这个程序依赖的动态库删除,程序会继续正常运行还是会崩溃 ?

当程序运行的时候,如果将可执行文件覆盖或者将程序依赖的动态库覆盖,程序会继续正常运行还是会崩溃 ?

这两个问题中有两个变量,一个是操作的对象,可执行文件还是依赖库;一个是操作的类型,把文件删除还是把文件覆盖。

本文通过实验的方式来记录这 4 中情况。

先列出结论,如下:

操作对象

删除

覆盖: cp new old

覆盖: mv new old

可执行文件

程序继续运行,不崩溃

操作失败,提示文件忙

程序继续运行,不崩溃

程序继续运行,不崩溃

动态库

程序继续运行,不崩溃

程序崩溃

程序继续运行,不崩溃

 

1 实验代码 

hello.c

#include 
#include 
#include 

void say_hello() {
    printf("hello\n");
    return;
}

 

hello.c 中实现了一个函数 say_hello(),将这个文件编译成一个动态库,名字为 libhello.so。

编译命令如下:

gcc -shared -fPIC -o libhello.so hello.c

hello.h

void say_hello();

hello.h 中是函数 say_hello() 的声明。这是使用 c 语言开发时常用的方式,头文件中是函数的声明,没有实现,c 文件是是函数的实现。引用库的时候包含头文件,然后再链接库。

main.c 

#include 
#include 
#include 
#include 
#include "hello.h"

int main() {
  say_hello();
  sleep(500);
  return 0;
}

main.c 中包含了 hello.h 头文件,然后在编译的时候需要链接 libhello.so 这个动态库,否则编译会失败,提示找不到函数 say_hello() 的定义。

编译命令如下:

gcc main.c libhello.so

编译完成之后,使用 ldd 查看 a.out 依赖的动态库时会提示 libhello.so 找不到,这个时候我们还需要把 libhello.so 的路径设置到 LD_LIBRARY_PATH 环境变量中,命令如下:

export LD_LIBRARY_PATH=/home/wyl/exelib/:$LD_LIBRARY_PATH

设置之后,再使用 ldd 查看 a.out 依赖的库,就能看奥 libhello.so 的位置了。

2 实验记录

2.1 删除可执行文件 

2.1.1 rm -rf 删除文件 

 程序运行之后,通过 ps -ef |grep a.out 可以查看进程的 pid。得到进程的 pid 之后,就可以使用命令 cat /proc/[pid]/maps 看到进程的文件映射信息。如下图所示,能看到进程中映射的 a.out 信息。

linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗_第1张图片

然后删除 a.out,再使用 cat /proc/[pid]/maps 查看文件映射信息,可以看到 a.out 信息后边增加了一个标记 deleted。

这个时候程序没有崩溃,还在运行。

a.out 也没有真正从磁盘删除,只有 a.out 退出之后,这个文件没有程序使用之后,文件才会真正从磁盘删除。

linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗_第2张图片

什么信息能佐证文件是不是真正从磁盘删除呢,可以通过查看 inode 号。ls -i a.out 可以查看一个文件的 inode,然后使用 lsof | grep xxx 来过滤这个 inode 号,如果 inode 存在,说明文件没有被删除;否则,说明被删除了。

 

2.1.2 mv 移动文件 

mv 移动文件,把文件移动到另外一个目录,程序也会继续运行,不会崩溃。

如下图所示,是程序运行只后,执行 mv a.out a.out-bak,把文件重命名,这个时候能够看到系统能自动识别出来文件发生了重命名。

linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗_第3张图片

刚才的 mv,我们并没有改变 a.out 的目录。我们继续移动 a.out-bak 移动到其它挂载点的目录下,那么系统就显示 deleted 了,跟把 a.out 删除现象是一样的。

linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗_第4张图片

从上边的实验可以看出来,使用 mv 移动文件的时候,移动的目标位置也会影响系统的显示。

a.out 原本的路径是 /home/wyl/exelib,

第一次移动的时候是用的命令是 mv a.out a.out-bak,没有改变 a.out 的路径,这个时候系统是能自动识别出来的。

第二次移动的时候是用的命令是mv a.out-bak /run/,改变了 a.out 的路径,这个时候系统的显示和文件被删除是相同的。

在 linux 中移动文件,如果是在一个挂在点之内移动,那么就相当于给文件重名名,内核中的 inode 保持不变,系统能自动识别;

如果文件的移动跨了挂载点,那么就相当于将旧文件删除,然后创建了一个新的文件。

实验用的虚拟机的挂载点如下,可以看到 /home/wyl/exelib 所在的挂载点和 /run 所在的挂载点是不一样的。

linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗_第5张图片

 

2.2 覆盖可执行文件

 想到文件覆盖的话,我们能想到 cp new old 或者 mv new old。但是我们如果想要覆盖可执行文件的话,使用 cp 无法操作成功,提示文件正忙。我们只能使用 mv 的方式。

使用 mv 的方式覆盖文件之后,系统显示和文件被删除是一样的,都是在 a.out 后边标记了 deleted。

linux 运行的程序,把可执行文件或者动态库删除,程序会崩溃吗_第6张图片

2.3 删除或覆盖动态库

删除或者覆盖动态库的时候,和删除或者覆盖可执行文件的时候,现象是基本相同的。

只有一点不一样,就是 cp old.so new.so 时可以执行成功的,并且这个操作会导致程序崩溃。

mv 覆盖是删除旧的,创建新的;cp 覆盖是覆盖旧文件的内容。

 

你可能感兴趣的:(linux,服务器)