如何找到用到某个动态库的所有进程

要查找使用特定动态库(共享库)的所有进程,可以通过以下方法在 Linux 系统中实现:


方法 1:使用 lsof 命令(推荐)

1
sudo lsof /path/to/library.so

说明

  • 替换 /path/to/library.so 为动态库的完整路径(如 /usr/lib/libcrypto.so.1.1)。
  • 输出包含使用该库的进程 ID(PID)、进程名等信息。
  • 示例:
    1
    sudo lsof /usr/lib/libc.so.6  # 查找所有使用 libc.so.6 的进程

方法 2:扫描 /proc 文件系统

通过脚本遍历所有进程的映射文件:

1
2
3
4
5
6
7
#!/bin/bash
library_name="目标库名" # 如 libssl.so.3
for pid in $(ps -e -o pid | tail -n +2); do
if grep -q "$library_name" /proc/$pid/maps 2>/dev/null; then
echo "PID $pid: $(cat /proc/$pid/comm)"
fi
done

说明

  • 目标库名 替换为库的名称(如 libssl.so.3)。
  • 脚本会输出所有加载该库的进程 PID 和名称。
  • 需要 sudo 权限查看其他用户的进程。

方法 3:使用 fuser 命令

1
sudo fuser -v /path/to/library.so

说明

  • 输出显示使用该文件的进程及用户信息。
  • 需要库的完整路径

方法 4:组合命令(快速查找)

1
pgrep -f "$(realpath /path/to/library.so)" | xargs ps -p

说明

  • realpath 解析库的绝对路径。
  • pgrep 匹配路径,ps 显示进程详情。

常见问题解决

  1. 找不到库路径

    • 使用 ldconfig -p | grep 库名 查找库的完整路径:
      1
      ldconfig -p | grep libssl
  2. 权限不足

    • 所有命令均需 sudo 以查看系统级进程。
  3. 库被多个进程使用

    • 结合 pstree 查看父子进程关系:
      1
      sudo lsof /path/to/library.so | awk '{print $2}' | xargs pstree -p

示例输出

1
2
3
4
$ sudo lsof /usr/lib/libc.so.6
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 1234 root mem REG 8,1 2029224 123456 /usr/lib/libc.so.6
python 5678 user mem REG 8,1 2029224 123456 /usr/lib/libc.so.6

通过以上方法,可快速定位使用特定动态库的进程。推荐优先使用 lsoffuser 命令。

是否有c函数接口支持

在 Linux 系统中,没有直接的标准 C 库函数可以查询使用特定动态库的所有进程。但可以通过以下方法间接实现类似功能:

1. 使用 /proc 文件系统(推荐)

这是最接近 C 接口的解决方案,通过读取 /proc 文件系统获取信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <ctype.h>

int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <library_name>\n", argv[0]);
return 1;
}

const char *target_lib = argv[1];
DIR *proc_dir = opendir("/proc");

if (!proc_dir) {
perror("opendir");
return 1;
}

struct dirent *entry;
while ((entry = readdir(proc_dir))) {
// 只处理 PID 目录(数字名称)
if (entry->d_type != DT_DIR) continue;

char *endptr;
long pid = strtol(entry->d_name, &endptr, 10);
if (*endptr != '\0') continue; // 跳过非数字目录

// 构建 maps 文件路径
char maps_path[256];
snprintf(maps_path, sizeof(maps_path), "/proc/%s/maps", entry->d_name);

FILE *maps_file = fopen(maps_path, "r");
if (!maps_file) continue; // 进程可能已退出

char line[1024];
int found = 0;
while (fgets(line, sizeof(line), maps_file)) {
if (strstr(line, target_lib)) {
found = 1;
break;
}
}
fclose(maps_file);

if (found) {
// 获取进程名
char comm_path[256];
char comm[256] = "unknown";
snprintf(comm_path, sizeof(comm_path), "/proc/%s/comm", entry->d_name);

FILE *comm_file = fopen(comm_path, "r");
if (comm_file) {
fgets(comm, sizeof(comm), comm_file);
// 移除换行符
comm[strcspn(comm, "\n")] = 0;
fclose(comm_file);
}

printf("PID: %s, Name: %s\n", entry->d_name, comm);
}
}

closedir(proc_dir);
return 0;
}

编译运行:

1
2
gcc find_lib_users.c -o find_lib_users
sudo ./find_lib_users libc.so.6

2. 使用 libproc 库(更高级)

部分 Linux 发行版提供 libproc 库(在 libprocps-dev 或类似包中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <proc/readproc.h>

void find_processes_using_lib(const char *libname) {
PROCTAB *proc = openproc(PROC_FILLCOM | PROC_FILLSTAT);
proc_t *proc_info;

while ((proc_info = readproc(proc, NULL))) {
if (proc_info->cmdline) {
for (int i = 0; proc_info->cmdline[i]; i++) {
if (strstr(proc_info->cmdline[i], libname)) {
printf("PID: %d, Name: %s\n",
proc_info->tid,
proc_info->cmd);
break;
}
}
}
freeproc(proc_info);
}

closeproc(proc);
}

3. 系统调用组合

虽然没有单一的系统调用,但可以组合使用:

1
2
3
4
5
6
7
8
9
10
11
12
#include <sys/syscall.h>

// 获取所有进程 ID
FILE *pids = popen("ps -e -o pid=", "r");

// 检查每个进程的 maps
while (fgets(line, sizeof(line), pids)) {
pid_t pid = atoi(line);
char maps_path[50];
sprintf(maps_path, "/proc/%d/maps", pid);
// 打开并解析 maps 文件...
}

注意事项

  1. 需要 root 权限:查看其他用户的进程需要特权
  2. 进程瞬态性:进程可能在扫描过程中退出
  3. 路径匹配
    • 使用库的完整路径更准确(如 /usr/lib/libc.so.6
    • 部分匹配可能误报(如 libssl.so 可能匹配 libssl.so.1.1
  4. 效率:扫描所有进程在大型系统上可能有性能影响

虽然标准 C 库没有直接提供此功能,但通过 /proc 文件系统可以可靠地实现该功能,这也是大多数系统工具(如 lsoffuser)的内部实现方式。