我正在编写一个内核模块来获取 pid 列表及其完整进程名称。
proc_pid_cmdline()
给出了完整的进程名称;使用相同的函数/proc/*/cmdline
可以获得完整的进程名称。 (struct task_struct) -> comm
给出了它是什么进程的提示,但不是完整的路径。
我已经包含了函数名称,但它给出了错误,因为它不知道在哪里可以找到该函数。
如何在模块中使用
proc_pid_cmdline()
?
你不应该打电话给
proc_pid_cmdline()
。
它是fs/proc/base.c
中的
非公共函数:
static int proc_pid_cmdline(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
但是,它的作用很简单:
get_cmdline(task, m->buf, PAGE_SIZE);
但这不太可能返回完整路径,并且不可能在每种情况下都确定完整路径。 arg[0] 值可能会被覆盖,文件可能会被删除或移动等。进程可能会以模糊原始命令行的方式执行 exec() 以及各种其他问题。
扫描我的 Fedora 20 系统 /proc/*/cmdline 会发现各种不太有用的结果:
-F
BUG:
WARNING: at
WARNING: CPU:
INFO: possible recursive locking detecte
ernel BUG at
list_del corruption
list_add corruption
do_IRQ: stack overflow:
ear stack overflow (cur:
eneral protection fault
nable to handle kernel
ouble fault:
RTNL: assertion failed
eek! page_mapcount(page) went negative!
adness at
NETDEV WATCHDOG
ysctl table check failed
: nobody cared
IRQ handler type mismatch
Machine Check Exception:
Machine check events logged
divide error:
bounds:
coprocessor segment overrun:
invalid TSS:
segment not present:
invalid opcode:
alignment check:
stack segment:
fpu exception:
simd exception:
iret exception:
/var/log/messages
--
/usr/bin/abrt-dump-oops
-xtD
我已经成功解决了这个问题的版本。我想访问所有 PID 的
cmdline
,但在内核本身内(而不是问题所述的 内核模块),但也许这些原则也可以应用于内核模块?
我所做的是,我将以下功能添加到
fs/proc/base.c
int proc_get_cmdline(struct task_struct *task, char * buffer) {
int i;
int ret = proc_pid_cmdline(task, buffer);
for(i = 0; i < ret - 1; i++) {
if(buffer[i] == '\0')
buffer[i] = ' ';
}
return 0;
}
然后我在
include/linux/proc_fs.h
int proc_get_cmdline(struct task_struct *, char *);
此时,我可以访问内核中所有进程的
cmdline
。
要访问task_struct
,也许你可以参考kernel: effective way to find task_struct by pid?。
一旦您拥有
task_struct
,您应该能够执行以下操作:
char cmdline[256];
proc_get_cmdline(task, cmdline);
if(strlen(cmdline) > 0)
printk(" cmdline :%s\n", cmdline);
else
printk(" cmdline :%s\n", task->comm);
我能够通过这种方式获取所有进程的命令行。
获取进程背后的二进制文件的完整路径。
char * exepathp;
struct file * exe_file;
struct mm_struct *mm;
char exe_path [1000];
//straight up stolen from get_mm_exe_file
mm = get_task_mm(current);
down_read(&mm->mmap_sem); //lock read
exe_file = mm->exe_file;
if (exe_file) get_file(exe_file);
up_read(&mm->mmap_sem); //unlock read
//reduce exe path to a string
exepathp = d_path( &(exe_file->f_path), exe_path, 1000*sizeof(char) );
其中 current 是您感兴趣的进程的任务结构。变量 exepathp 获取完整路径的字符串。这与进程 cmd 略有不同,这是加载以启动进程的二进制文件的路径。将此路径与进程 cmd 结合起来应该会为您提供完整路径。
以线程安全的方式获取内核中进程的路径是可以管理的。
检查我在项目中是如何做到的:
获取当前任务的路径
在我的项目中,我获取了“当前任务”的路径。如果您需要获取不同任务的路径,只需修改函数以获取 task_struct 作为参数并使用它来代替 current 。
如果您发现该项目有帮助,请随时为其加注星标;)