0%

pidof 源码分析

概述

执行ls -all $(which pidof),结果如下:

1
lrwxrwxrwx 1 root root 14 May 19  2021 /usr/bin/pidof -> /sbin/killall5

核心代码

killall5.c

Linux man page

pidof(8)_ find process ID of running program - Linux man page

Notes

pidof is actually the same program as killall5; the program behaves according to the name under which it is called.
When pidof is invoked with a full pathname to the program it should find the pid of, it is reasonably safe. Otherwise it is possible that it returns pids of running programs that happen to have the same name as the program you’re after but are actually other programs. Note that that the executable name of running processes is calculated with readlink(2), so symbolic links to executables will also match.

pidof实际上就是killall5,通过调用名称来执行不同操作。
源码:

1
2
3
4
5
6
7
8
9
10
11
12
/* Get program name. */
if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
progname++;

/* Now connect to syslog. */
openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);

/* Were we called as 'pidof' ? */
if (strcmp(progname, "pidof") == 0)
return main_pidof(argc, argv);

main_pidof

行为分析

使用strace打印系统调用,strace pidof 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
openat(AT_FDCWD, "156204/stat", O_RDONLY) = 4
newfstatat(4, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
read(4, "156204 (pidof) R 156201 156201 1"..., 4096) = 316
read(4, "", 3072) = 0
close(4) = 0
openat(AT_FDCWD, "156204/cmdline", O_RDONLY) = 4
newfstatat(4, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
read(4, "pidof\0001\0", 1024) = 8
close(4) = 0
newfstatat(AT_FDCWD, "/proc/156204/exe", {st_mode=S_IFREG|0755, st_size=27016, ...}, 0) = 0
readlink("/proc/156204/exe", "/usr/sbin/killall5", 4096) = 18
getdents64(3, 0x559a95f732d0 /* 0 entries */, 32768) = 0
close(3) = 0
getuid() = 1000
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0
write(1, "151675\n", 7151675
) = 7
exit_group(0) = ?
+++ exited with 0 +++

遍历/proc/,读取了/proc/$pid/stat/proc/$pid/cmdline的文件内容,以及/proc/$pid/exe的符号链接。

源码

  1. 先调用readprocfopen /proc/$pid/stat/proc/$pid/cmdline
  2. 再调用pidofreadlink /proc/$pid/exe

参考

Get PID of a process by giving the name - C Board