在proc根目录下,以数字命名的目录表示当前一个运行的进程,目录名为进程的pid。其内的目录和文件给出了一些关于进程的信息。
ywx@ywx:/proc/1500$ ls
ls: cannot read symbolic link cwd: Permission denied
ls: cannot read symbolic link root: Permission denied
ls: cannot read symbolic link exe: Permission denied
attr cpuset latency mountstats sched status
auxv cwd limits net schedstat syscall
cgroup environ loginuid oom_adj sessionid task
clear_refs exe maps oom_score smaps wchan
cmdline fd mem pagemap stack
comm fdinfo mountinfo personality stat
coredump_filter io mounts root statm
我们可以看到该目录下有这么些文件。其中attr、fd、fdinfo、task为目录,cwd、root为指向目录的链接,exe为指向文件的链接,其余为一般文件。对于一些文件或目录的权限(查看或者修改的权限)是该进程的创建者才有,例如auxv等文件或目录只有创建该进程的用户才有查看或修改的权限,而其他一些文件则对所有用户可读权限。关于这些文件或目录的权限,我们可以在内核中找到(fs/proc/base.c, tid_base_stuff数组)。
在2.6.35源码fs/proc/base.c中;http://lxr.linux.no/linux+v2.6.35/fs/proc/base.c
static const struct pid_entry tid_base_stuff[] = {
DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
REG("environ", S_IRUSR, proc_environ_operations),
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
INF("limits", S_IRUSR, proc_pid_limits),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
INF("syscall", S_IRUSR, proc_pid_syscall),
#endif
INF("cmdline", S_IRUGO, proc_pid_cmdline),
ONE("stat", S_IRUGO, proc_tid_stat),
ONE("statm", S_IRUGO, proc_pid_statm),
REG("maps", S_IRUGO, proc_maps_operations),
#ifdef CONFIG_NUMA
REG("numa_maps", S_IRUGO, proc_numa_maps_operations),
#endif
REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations),
LNK("cwd", proc_cwd_link),
LNK("root", proc_root_link),
LNK("exe", proc_exe_link),
REG("mounts", S_IRUGO, proc_mounts_operations),
REG("mountinfo", S_IRUGO, proc_mountinfo_operations),
#ifdef CONFIG_PROC_PAGE_MONITOR
REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
REG("smaps", S_IRUGO, proc_smaps_operations),
REG("pagemap", S_IRUSR, proc_pagemap_operations),
#endif
#ifdef CONFIG_SECURITY
DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
#endif
#ifdef CONFIG_KALLSYMS
INF("wchan", S_IRUGO, proc_pid_wchan),
#endif
#ifdef CONFIG_STACKTRACE
ONE("stack", S_IRUSR, proc_pid_stack),
#endif
#ifdef CONFIG_SCHEDSTATS
INF("schedstat", S_IRUGO, proc_pid_schedstat),
#endif
#ifdef CONFIG_LATENCYTOP
REG("latency", S_IRUGO, proc_lstats_operations),
#endif
#ifdef CONFIG_PROC_PID_CPUSET
REG("cpuset", S_IRUGO, proc_cpuset_operations),
#endif
#ifdef CONFIG_CGROUPS
REG("cgroup", S_IRUGO, proc_cgroup_operations),
#endif
INF("oom_score", S_IRUGO, proc_oom_score),
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUSR, proc_sessionid_operations),
#endif
#ifdef CONFIG_FAULT_INJECTION
REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
#endif
#ifdef CONFIG_TASK_IO_ACCOUNTING
INF("io", S_IRUGO, proc_tid_io_accounting),
#endif
};
下面来详细每一个文件和目录的作用。
1.cmdline文件
该文件包含的是该进程的命令行参数,包括进程的启动路径(argv[0])。也就是说例如你在命令行上运行一个hello程序:
打开一个终端:
ywx@ywx:~/desktop$ cat hello.c
#include <stdio.h>
#include <wait.h>
int main()
{
int i=0;
for(i=0;i<100;i++)
{
printf("hello world\n");
sleep(2);
}
return 0;
}
ywx@ywx:~/desktop$ gcc hello.c -o hello
ywx@ywx:~/desktop$ ./hello one two
hello world
hello world
打开另一个终端,查看当前进程的进程号:得知进程号为
ywx@ywx:~/Desktop$ ps -A | grep hello
2752 pts/0 00:00:00 hello
然后进入/proc/2752进程下面:
ywx@ywx:~/Desktop$ cd /proc/2752
ywx@ywx:/proc/2752$ cat cmdline
./helloonetwoywx@ywx:/proc/2752$
可以看到cmdline里的内容为 “./helloonetwo”,正是命令行的参数。可能你会疑问为什么参数没有分开??那是因为cat欺骗了你。我们可以将cmdline复制到desktop下,然后用vim查看发现是这样的:
./hello^@one^@two^@
也就是说,实际上每个参数之间是有东西隔开的,只不过cat将其忽略而已,而vim可以给你标识出东西,但vim本身不显示罢了。我们可以通过编程读取该文件。下面给出程序。
我们一个字符一个字符的读取文件内容直到文件结束,在读取每一个字符的时候,打印其字符和对应的数值。
// ywx@ywx:~/desktop$ cat readcmd.c
#include <stdio.h>// std io fopen() snprintf() feof() perrof()
int main(int argc,char *argv[])
{
FILE *fp;
char path[80];
unsigned char ch;
snprintf(path,80,"/home/ywx/desktop/cmdline");//将cmdline中内容写入path数组中,并在path的结尾添 加字符结束符"\0"
if((fp=fopen(path,"r")) == NULL)
{
perror("fopen");
return 0;
}
while(!feof(fp)) //判断当前操作位置是否为文件的末尾,如果是,返回一个非零值
{
ch=fgetc(fp);//从stream流中读取一个字符,操作位置向下移动一个
printf("%c %d\n",ch,ch);
}
fclose(fp);
return 0;
}
ywx@ywx:~/Desktop$ gcc readcmd.c -o readcmd
ywx@ywx:~/Desktop$ ./readcmd
. 46
/ 47
h 104
e 101
l 108
l 108
o 111
0
o 111
n 110
e 101
0
t 116
w 119
o 111
0
� 255
由此我们可以看到并非是每个参数之间没有间隔,而是以字符"\0"作为间隔。所以如果我们在某一个程序中想读取进程的命令行参数,我们只需要知道该进程的pid,然后进入proc文件系统的该pid对应的目录下,编程读写读取cmdline文件就可以了。