Linux proc文件系统说明

在Linux上,proc是一个伪文件系统,提供了访问内核数据的方法,一般挂载在“/proc”目录,其中的大部分内容是只读的,挂载(mount)信息可能为:

proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

proc文件系统支持如下挂载选项:

hidepid=_n
gid=_gid

_n设置访问“/proc/[pid]”目录的权限,可以取值为0、1、2,0为默认值,表示任何人可以访问“/proc/[pid]”的所有目录,1表示只能访问访问者本身所属进程对应目录的内容,其它进程的目录的内容一概不能访问,这隐藏了敏感文件的信息如“/proc/[pid]/cmdline”、“/proc/[pid]/status”等,2类似于1,但是“/proc/[pid]”目录对于其它用户来说是不见的,也就是说不能直观地看到pid值,但PID确实是存在的,可以通过其它方法如kill -0 $PID获取,虽然隐藏了UID、GID,但是仍然可以通过命令stat获取,这增加了攻击者获取进程信息的难度。 
_gid设置组ID,授权其成员可以获取进程信息(man sudoers)。

下面列举“/proc”文件系统下的文件和目录。

1、pid目录

“/proc/[pid]”,目录,pid为进程的数字ID,是个数值,每个运行着的进程都有这么一个目录。 
“/proc/[pid]/attr”,目录,提供了安全相关的属性,可读可写,以支持安全模块如SELinux等,需配置CONFIG_SECURITY。 
“/proc/[pid]/attr/current”,文件,当前的安全相关的属性。 
“/proc/[pid]/attr/exec”,文件,执行命令execve时设置的安全相关的属性。 
“/proc/[pid]/attr/fscreate”,文件,执行命令openmkdirsymlinkmknod时设置的安全相关的属性。 
“/proc/[pid]/attr/keycreate”,文件,执行命令add_key时设置的安全相关的属性。 
“/proc/[pid]/attr/prev”,文件,最后一次执行命令execve时的安全相关的属性,即前一个“/proc/[pid]/attr/current”。 
“/proc/[pid]/attr/sockcreate”,文件,创建socket时设置的安全相关的属性。 
“/proc/[pid]/auxv”,文件,ELF解释器信息,格式为一个unsigned long类型的ID加一个unsigned long类型的值,最后为两个0(man getauxval)。 
“/proc/[pid]/cgroup”,文件,进程所属的控制组,格式为冒号分隔的三个字段,分别是结构ID、子系统、控制组,需配置CONFIG_CGROUPS。 
“/proc/[pid]/clear_refs”,文件,只写,只用于进程的拥有者,清除用于估算内存使用量的PG_Referenced和ACCESSED/YOUNG,有1、2、3、4四种策略,1表示清除相关的所有页,2表示清除相关的匿名页,3表示清除相关的映射文件的页,4表示清除相关的soft-dirty的页,需配置CONFIG_PROC_PAGE_MONITOR。 
“/proc/[pid]/cmdline”,文件,只读,保存启动进程的完整的命令行字符串,如果是僵尸进程,这个文件为空。 
“/proc/[pid]/comm”,文件,进程的命令名,不同的线程(man clone prctl pthread_setname_np)可能有不同的线程名,位置在“task/[tid]/comm”,名字长度超过TASK_COMM_LEN时会被截断。 
“/proc/[pid]/coredump_filter”,文件,coredump过滤器,如00000033(man core),不同的二进制位表示过滤不同的信息。 
“/proc/[pid]/cpuset”,文件,控制CPU和内存的节点(man cpuset)。 
“/proc/[pid]/cwd”,目录,符号链接到当前工作目录。 
“/proc/[pid]/environ”,文件,环境变量。 
“/proc/[pid]/exe”,文件,符号链接到启动进程的完整命令。 
“/proc/[pid]/fd/”,目录,包含当前的fd,这些fd符号链接到真正打开的文件。 
“/proc/[pid]/fdinfo/”,目录,包含当前fd的信息,不同类型的fd信息不同。 
“/proc/[pid]/io”,文件,IO信息。 
“/proc/[pid]/gid_map”,文件,从用户命名空间映射的组ID的信息(man user_namespaces)。 
“/proc/[pid]/limits”,文件,资源软、硬限制(man getrlimit)。 
“/proc/[pid]/map_files/”,目录,包括一些内存映射文件(man mmap),文件名格式为BeginAddress-EndAddress,符号链接到映射的文件,需要配置CONFIG_CHECKPOINT_RESTORE。 
“/proc/[pid]/maps”,文件,内存映射信息,下面“proc-pid-maps”详细介绍。 
“/proc/[pid]/mem”,文件,用于通过open、read、lseek访问进程的内存页。 
“/proc/[pid]/mountinfo”,文件,挂载信息,格式为36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue,以空格作为分隔符,从左到右各字段的意思分别是唯一挂载ID、父挂载ID、文件系统的设备主从号码、文件系统中挂载的根节点、相对于进程根节点的挂载点、挂载权限等挂载配置、可选配置、短横线表示前面可选配置的结束、文件系统类型、文件系统特有的挂载源或者为none、额外配置。 
/proc/[pid]/mounts,文件,挂载在当前进程的文件系统列表,格式参照(man fstab)。 
/proc/[pid]/mountstats,文件,挂载信息,格式形如device /dev/sda7 mounted on /home with fstype ext3 [statistics]。 
/proc/[pid]/ns/,目录,保存了每个名字空间的入口,详见(man namespaces)。 
/proc/[pid]/numa_maps,文件,numa即Non Uniform Memory Access,详见(man numa)。 
/proc/[pid]/oom_adj,文件,调整OOM分数,OOM即Out Of Memory,发生OOM时OOM Killer根据OOM分数杀掉分数高的进程,默认值为0,会继承自父进程的设置。 
/proc/[pid]/oom_score,文件,OOM分数。 
/proc/[pid]/oom_score_adj,文件,OOM分值介于-1000到1000之间。 
/proc/[pid]/pagemap,文件,当前进程的虚拟内存页映射信息,需要配置CONFIG_PROC_PAGE_MONITOR。 
/proc/[pid]/personality,文件,进行执行域。 
/proc/[pid]/root,目录,链接到了当前进程的根目录。 
/proc/[pid]/seccomp,文件,seccomp模式下允许的系统调用只有read、write、_exit、sigreturn,Linux 2.6.23已弃用这个文件,由prctl替代。 
/proc/[pid]/setgroups,文件,详见(man user_namespaces)。 
“/proc/[pid]/smaps”,文件,内存映射信息,类似于pmap命令,需要配置CONFIG_PROC_PAGE_MONITOR,下面“proc-pid-smaps”详细介绍。 
/proc/[pid]/stack,文件,内核空间的函数调用堆栈,需要配置CONFIG_STACKTRACE。 
/proc/[pid]/stat,文件,进程状态信息,用于ps命令。 
/proc/[pid]/statm,文件,进程内存使用信息,以空格分隔的7个数字,从左到右分别表示程序总大小、常驻内存大小、共享内存页大小、text code、library、data + stack、dirty pages。 
/proc/[pid]/status,文件,可读性好的进程相关信息,下面“proc-pid-status”详细介绍。 
/proc/[pid]/syscall,文件,系统调用相关信息,需要配置CONFIG_HAVE_ARCH_TRACEHOOK。 
/proc/[pid]/task,目录,每个线程一个子目录,目录名为线程ID。 
/proc/[pid]/timers,文件,POSIT定时器列表,包括定时器ID、信号等信息。 
/proc/[pid]/uid_map,文件,用户ID映射信息,详见(man user_namespaces)。 
/proc/[pid]/gid_map,文件,组ID映射信息,详见(man user_namespaces)。 
/proc/[pid]/wchan,文件,进程休眠时内核中相应位置的符号表示,如do_wait。

2、proc-pid-maps

maps文件内容的格式如下:

       address                      perms offset    dev    inode        pathname
       00400000-00452000 r-xp 00000000 08:02 173521      /usr/bin/dbus-daemon
       00651000-00652000 r--p 00051000 08:02 173521      /usr/bin/dbus-daemon
       00652000-00655000 rw-p 00052000 08:02 173521      /usr/bin/dbus-daemon
       00e03000-00e24000 rw-p 00000000 00:00 0           [heap]
       00e24000-011f7000 rw-p 00000000 00:00 0           [heap]
       ...
       35b1800000-35b1820000 r-xp 00000000 08:02 135522  /usr/lib64/ld-2.15.so
       35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522  /usr/lib64/ld-2.15.so
       35b1a20000-35b1a21000 rw-p 00020000 08:02 135522  /usr/lib64/ld-2.15.so
       35b1a21000-35b1a22000 rw-p 00000000 00:00 0
       35b1c00000-35b1dac000 r-xp 00000000 08:02 135870  /usr/lib64/libc-2.15.so
       35b1dac000-35b1fac000 ---p 001ac000 08:02 135870  /usr/lib64/libc-2.15.so
       35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870  /usr/lib64/libc-2.15.so
       35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870  /usr/lib64/libc-2.15.so
       ...
       f2c6ff8c000-7f2c7078c000 rw-p 00000000 00:00 0    [stack:986]
       ...
       7fffb2c0d000-7fffb2c2e000 rw-p 00000000 00:00 0   [stack]
       7fffb2d48000-7fffb2d49000 r-xp 00000000 00:00 0   [vdso]

address字段表示进程中内存映射占据的地址空间,格式为十六进制的BeginAddress-EndAddress。 
perms字段表示权限,共四个字符,依次为rwxs或rwxp,其中r为read,w为write,x为execute,s为shared,p为private,对应位置没有权限时用一个短横线代替。 
offset字段表示内存映射地址在文件中的字节偏移量。 
dev字段表示device,格式为major:minor。 
inode字段表示对应device的inode,0表示内存映射区域没有关联的inode,如未初始化的BSS数据段就是这种情况。 
pathname字段用于内存映射的文件,对于ELF格式的文件来说,可以通过命令readelf -l查看ELF程序头部的Offset字段,与maps文件的offset字段作对比。pathname可能为空,表示匿名映射,这种情况下难以调试进程,如gdb、strace等命令。除了正常的文件路径之外,pathname还可能是下面的值:

[stack]    初始进程(主线程)的stack
[stack:<tid>]    线程IDtidstack
[vdso]    Virtual Dynamically linked Shared Object
[heap]    进程的heap

3、proc-pid-smaps

smaps文件内容的格式如下:

                      00400000-0048a000 r-xp 00000000 fd:03 960637       /bin/bash
                      Size:                552 kB
                      Rss:                 460 kB
                      Pss:                 100 kB
                      Shared_Clean:        452 kB
                      Shared_Dirty:          0 kB
                      Private_Clean:         8 kB
                      Private_Dirty:         0 kB
                      Referenced:          460 kB
                      Anonymous:             0 kB
                      AnonHugePages:         0 kB
                      Swap:                  0 kB
                      KernelPageSize:        4 kB
                      MMUPageSize:           4 kB
                      Locked:                0 kB

第一行内容同maps文件,剩下的是各种类型的内存映射大小,其中Rss表示当前常驻在RAM中的内存,Pss表示进程按比例共享的内存。

4、proc-pid-status

status文件内容的格式如下(查看当前shell命令所在进程的信息):

                  $ cat /proc/$$/status
                  Name:   bash
                  State:  S (sleeping)
                  Tgid:   3515
                  Pid:    3515
                  PPid:   3452
                  TracerPid:      0
                  Uid:    1000    1000    1000    1000
                  Gid:    100     100     100     100
                  FDSize: 256
                  Groups: 16 33 100
                  VmPeak:     9136 kB
                  VmSize:     7896 kB
                  VmLck:         0 kB
                  VmPin:         0 kB
                  VmHWM:      7572 kB
                  VmRSS:      6316 kB
                  VmData:     5224 kB
                  VmStk:        88 kB
                  VmExe:       572 kB
                  VmLib:      1708 kB
                  VmPMD:         4 kB
                  VmPTE:        20 kB
                  VmSwap:        0 kB
                  Threads:        1
                  SigQ:   0/3067
                  SigPnd: 0000000000000000
                  ShdPnd: 0000000000000000
                  SigBlk: 0000000000010000
                  SigIgn: 0000000000384004
                  SigCgt: 000000004b813efb
                  CapInh: 0000000000000000
                  CapPrm: 0000000000000000
                  CapEff: 0000000000000000
                  CapBnd: ffffffffffffffff
                  CapAmb:   0000000000000000
                  Seccomp:        0
                  Cpus_allowed:   00000001
                  Cpus_allowed_list:      0
                  Mems_allowed:   1
                  Mems_allowed_list:      0
                  voluntary_ctxt_switches:        150
                  nonvoluntary_ctxt_switches:     545

5、bus目录

/proc/bus,目录,已安装的总线。 
/proc/bus/pccard 
/proc/bus/pccard/drivers 
/proc/bus/pci 
/proc/bus/pci/devices

6、net目录

/proc/net,目录,网络伪文件系统相关。 
/proc/net/arp 
/proc/net/dev 
/proc/net/dev_mcast 
/proc/net/igmp 
/proc/net/rarp 
/proc/net/raw 
/proc/net/snmp 
/proc/net/tcp 
/proc/net/udp 
/proc/net/unix 
/proc/net/netfilter/nfnetlink_queue

7、sys目录

/proc/sys,目录,系统变量相关信息,详细如下。 
/proc/sys/abi 
/proc/sys/debug 
/proc/sys/dev 
/proc/sys/fs 
/proc/sys/fs/binfmt_misc 
/proc/sys/fs/dentry-state 
/proc/sys/fs/dir-notify-enable 
/proc/sys/fs/dquot-max 
/proc/sys/fs/dquot-nr 
/proc/sys/fs/epoll 
/proc/sys/fs/file-max 
/proc/sys/fs/file-nr 
/proc/sys/fs/inode-max 
/proc/sys/fs/inode-nr 
/proc/sys/fs/inode-state 
/proc/sys/fs/inotify 
/proc/sys/fs/lease-break-time 
/proc/sys/fs/leases-enable 
/proc/sys/fs/mqueue 
/proc/sys/fs/nr_open 
/proc/sys/fs/overflowgid 
/proc/sys/fs/overflowuid 
/proc/sys/fs/pipe-max-size 
/proc/sys/fs/protected_hardlinks 
/proc/sys/fs/protected_symlinks 
/proc/sys/fs/suid_dumpable 
/proc/sys/fs/super-max 
/proc/sys/fs/super-nr 
/proc/sys/kernel 
/proc/sys/kernel/acct 
/proc/sys/kernel/auto_msgmni 
/proc/sys/kernel/cap_last_cap 
/proc/sys/kernel/cap-bound 
/proc/sys/kernel/core_pattern 
/proc/sys/kernel/core_uses_pid 
/proc/sys/kernel/ctrl-alt-del 
/proc/sys/kernel/dmesg_restrict 
/proc/sys/kernel/domainname 
/proc/sys/kernel/hostname 
/proc/sys/kernel/hotplug 
/proc/sys/kernel/htab-reclaim 
/proc/sys/kernel/kptr_restrict 
/proc/sys/kernel/l2cr 
/proc/sys/kernel/modprobe 
/proc/sys/kernel/modules_disabled 
/proc/sys/kernel/msgmax 
/proc/sys/kernel/msgmni 
/proc/sys/kernel/msgmnb 
/proc/sys/kernel/ngroups_max 
/proc/sys/kernel/ostype 
/proc/sys/kernel/osrelease 
/proc/sys/kernel/overflowgid 
/proc/sys/kernel/overflowuid 
/proc/sys/kernel/panic 
/proc/sys/kernel/panic_on_oops 
/proc/sys/kernel/pid_max 
/proc/sys/kernel/powersave-nap 
/proc/sys/kernel/printk 
/proc/sys/kernel/pty 
/proc/sys/kernel/pty/max 
/proc/sys/kernel/pty/nr 
/proc/sys/kernel/random 
/proc/sys/kernel/random/uuid 
/proc/sys/kernel/randomize_va_space 
/proc/sys/kernel/real-root-dev 
/proc/sys/kernel/reboot-cmd 
/proc/sys/kernel/rtsig-max 
/proc/sys/kernel/rtsig-nr 
/proc/sys/kernel/sched_rr_timeslice_ms 
/proc/sys/kernel/sched_rt_period_us 
/proc/sys/kernel/sched_rt_period_us 
/proc/sys/kernel/sem 
/proc/sys/kernel/sg-big-buff 
/proc/sys/kernel/shm_rmid_forced 
/proc/sys/kernel/shmall 
/proc/sys/kernel/shmmax 
/proc/sys/kernel/shmmni 
/proc/sys/kernel/sysctl_writes_strict 
/proc/sys/kernel/sysrq 
/proc/sys/kernel/version 
/proc/sys/kernel/threads-max 
/proc/sys/kernel/yama/ptrace_scope 
/proc/sys/kernel/zero-paged 
/proc/sys/net 
/proc/sys/net/core/bpf_jit_enable 
/proc/sys/net/core/somaxconn 
/proc/sys/proc 
/proc/sys/sunrpc 
/proc/sys/vm 
/proc/sys/vm/compact_memory 
/proc/sys/vm/drop_caches 
/proc/sys/vm/legacy_va_layout 
/proc/sys/vm/memory_failure_early_kill 
/proc/sys/vm/memory_failure_recovery 
/proc/sys/vm/oom_dump_tasks 
/proc/sys/vm/oom_kill_allocating_task 
/proc/sys/vm/overcommit_kbytes 
/proc/sys/vm/overcommit_memory 
/proc/sys/vm/overcommit_ratio 
/proc/sys/vm/panic_on_oom 
/proc/sys/vm/swappiness

N、其它

/proc/apm,文件,apm即Advanced Power Management,需要配置CONFIG_APM。 
/proc/buddyinfo,文件,用于诊断内存碎片问题。 
/proc/cmdline,文件,系统启动时传递给Linux内核的参数,如lilo、grub等boot管理模块。 
/proc/config.gz,文件,内核编译配置选项,需要配置CONFIG_IKCONFIG_PROC。 
/proc/crypto,文件,内核加密API提供的加密列表。 
/proc/cpuinfo,文件,CPU和系统架构信息,lscpu命令使用这个文件。 
/proc/devices,文件,设备相关信息。 
/proc/diskstats,文件,磁盘状态。 
/proc/dma,文件,dma即Direct Memory Access。 
/proc/driver/rtc,文件,系统运行时配置。 
/proc/execdomains,文件,执行域列表。 
/proc/fb,文件,Frame Buffer信息,需要配置CONFIG_FB。 
/proc/filesystems,文件,内核支持的文件系统类型(man filesystems)。 
/proc/fs,目录,挂载的文件系统信息。 
/proc/ide,目录,用于IDE接口。 
/proc/interrupts,文件,每个CPU每个IO的中断信息。 
/proc/iomem,文件,IO内存映射信息。 
/proc/ioports,文件,IO端口信息。 
/proc/kallsyms,文件,用于动态链接和和模块绑定的符号定义。 
/proc/kcore,文件,系统中ELF格式的物理内存。 
/proc/kmsg,文件,内核信息,dmsg命令使用这个文件。 
/proc/kpagecount,文件,每个物理页帧映射的次数,需要配置CONFIG_PROC_PAGE_MONITOR。 
/proc/kpageflags,文件,每个物理页帧的掩码,需要配置CONFIG_PROC_PAGE_MONITOR。 
/proc/ksyms,文件,同kallsyms。 
/proc/loadavg,文件,工作负荷。 
/proc/locks,文件,当前文件锁的状态。 
/proc/malloc,文件,需要配置CONFIG_DEBUG_MALLOC。 
/proc/meminfo,文件,系统内存使用统计,free命令使用了这个文件。 
/proc/modules,文件,系统加载的模块信息,相关命令为lsmod。 
/proc/mounts,文件,链接到了/self/mounts。 
/proc/mtrr,文件,Memory Type Range Registers。 
/proc/partitions,文件,分区信息。 
/proc/pci,文件,PCI接口设备。 
/proc/profile,文件,用于readprofile命令作性能分析。 
/proc/scsi,目录,SCSI接口设备。 
/proc/scsi/scsi 
/proc/scsi/[drivername] 
/proc/self,目录,链接到了当前进程所在的目录。 
/proc/slabinfo,文件,内核缓存信息,需要配置CONFIG_SLAB。 
/proc/stat,文件,系统信息统计。 
/proc/swaps,文件,使用的交换空间。 
/proc/sysrq-trigger,文件,可写,触发系统调用。 
/proc/sysvipc,目录,包括msg、sem、shm三个文件,为System V IPC对象。 
/proc/thread-self,文件,链接到了当前进程下的task目录中的线程文件。 
/proc/timer_list,文件,还在运行着的定时器列表。 
/proc/timer_stats,文件,定时器状态。 
/proc/tty,目录,tty设备相关。 
/proc/uptime,文件,系统更新时间和进程空闲时间。 
/proc/version,文件,内核版本信息。 
/proc/vmstat,文件,内存统计信息,以键值对形式显示。 

/proc/zoneinfo,文件,内存区块信息,用于分析虚拟内存的行为。

使用 /proc 文件系统来访问 Linux 内核的内容,这个虚拟文件系统,在内核空间和用户空间之间打开了一个通信窗口:

/proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux内核空间和用户间之间进行通信

在 /proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段,但是与普通文件不同的是,这些虚拟文件的内容都是动态创建的。本文对 /proc 虚拟文件系统进行了介绍,并展示了它的用法。

最初开发 /proc 文件系统是为了提供有关系统中进程的信息。但是由于这个文件系统非常有用,因此内核中的很多元素也开始使用它来报告信息,或启用动态运行时配置。

清单 1 是对 /proc 中部分元素进行一次交互查询的结果。它显示的是 /proc 文件系统的根目录中的内容。注意,在左边是一系列数字编号的文件。每个实际上都是一个目录,表示系统中的一个进程。由于在 GNU/Linux 中创建的第一个进程是 init 进程,因此它的 process-id 为 1。然后对这个目录执行一个 ls 命令,这会显示很多文件。每个文件都提供了有关这个特殊进程的详细信息。/proc 中另外一些有趣的文件有:cpuinfo,它标识了处理器的类型和速度;pci,显示在 PCI 总线上找到的设备;modules,标识了当前加载到内核中的模块。

另外,我们还可以使用 sysctl 来配置这些内核条目。/proc 文件系统并不是 GNU/Linux 系统中的惟一一个虚拟文件系统。在这种系统上,sysfs 是一个与 /proc 类似的文件系统,但是它的组织更好(从 /proc 中学习了很多教训)。不过 /proc 已经确立了自己的地位,因此即使 sysfs 与 /proc 相比有一些优点,/proc 也依然会存在。还有一个 debugfs 文件系统,不过(顾名思义)它提供的更多是调试接口。debugfs 的一个优点是它将一个值导出给用户空间非常简单(实际上这不过是一个调用而已)。

这些文件的解释和意义如下:

cmdline:系统启动时输入给内核命令行参数 
cpuinfo:CPU的硬件信息 (型号, 家族, 缓存大小等)  
devices:主设备号及设备组的列表,当前加载的各种设备(块设备/字符设备) 
dma:使用的DMA通道 
filesystems:当前内核支持的文件系统,当没有给 mount(1) 指明哪个文件系统的时候, mount(1) 就依靠该文件遍历不同的文件系统
interrupts :中断的使用及触发次数,调试中断时很有用 
ioports I/O:当前在用的已注册 I/O 端口范围 
kcore:该伪文件以 core 文件格式给出了系统的物理内存映象(比较有用),可以用 GDB 查探当前内核的任意数据结构。该文件的总长度是物理内存 (RAM) 的大小再加上 4KB
kmsg:可以用该文件取代系统调用 syslog(2) 来记录内核日志信息,对应dmesg命令
kallsym:内核符号表,该文件保存了内核输出的符号定义, modules(X)使用该文件动态地连接和捆绑可装载的模块
loadavg:负载均衡,平均负载数给出了在过去的 1、 5,、15 分钟里在运行队列里的任务数、总作业数以及正在运行的作业总数。
locks:内核锁 。
meminfo物理内存、交换空间等的信息,系统内存占用情况,对应df命令。
misc:杂项 。
modules:已经加载的模块列表,对应lsmod命令 。
mounts:已加载的文件系统的列表,对应mount命令,无参数。
partitions:系统识别的分区表 。
slabinfo:sla池信息。
stat:全面统计状态表,CPU内存的利用率等都是从这里提取数据。对应ps命令。
swaps:对换空间的利用情况。 
version:指明了当前正在运行的内核版本。


可加载内核模块(LKM)是用来展示 /proc 文件系统的一种简单方法,这是因为这是一种用来动态地向 Linux 内核添加或删除代码的新方法。LKM 也是 Linux 内核中为设备驱动程序和文件系统使用的一种流行机制。如果你曾经重新编译过 Linux 内核,就可能会发现在内核的配置过程中,有很多设备驱动程序和其他内核元素都被编译成了模块。如果一个驱动程序被直接编译到了内核中,那么即使这个驱动程序没有运行,它的代码和静态数据也会占据一部分空间。但是如果这个驱动程序被编译成一个模块,就只有在需要内存并将其加载到内核时才会真正占用内存空间。


集成到 /proc 文件系统中

内核程序员可以使用的标准 API,LKM 程序员也可以使用。

方法一:(create_proc_entry创建proc文件)

1.1 .创建目录:

[c]  view plain  copy
  1. struct proc_dir_entry *proc_mkdir(const char *name,  
  2.                 struct proc_dir_entry *parent);  

1.2 .创建proc文件:

[c]  view plain  copy
  1. struct proc_dir_entry *create_proc_entry( const char *name,  mode_t mode,  
  2.                 struct proc_dir_entry *parent );  

create_proc_entry函数用于创建一个一般的proc文件,其中name是文件名,比如“hello”,mode是文件模式,parent是要创建的proc文件的父目录(若parent = NULL则创建在/proc目录下)。create_proc_entry 的返回值是一个 proc_dir_entry 指针(或者为 NULL,说明在 create 时发生了错误)。然后就可以使用这个返回的指针来配置这个虚拟文件的其他参数,例如在对该文件执行读操作时应该调用的函数。

[html]  view plain  copy
  1. struct proc_dir_entry {  
  2.     ......  
  3.     const struct file_operations *proc_fops;    <==文件操作结构体  
  4.     struct proc_dir_entry *next, *parent, *subdir;  
  5.     void *data;  
  6.     read_proc_t *read_proc;                    <==读回调  
  7.     write_proc_t *write_proc;                  <==写回调  
  8.     ......  
  9. }; 

1.3 .删除proc文件/目录:

  1. void remove_dir_entry(const char *name, struct proc_dir_entry *parent);  

要从 /proc 中删除一个文件,可以使用 remove_proc_entry 函数。要使用这个函数,我们需要提供文件名字符串,以及这个文件在 /proc 文件系统中的位置(parent)


3、proc文件读回调函数

static int (*proc_read)(char *page, char **start,  off_t off, int count,  int *eof, void *data);


4、proc文件写回调函数

static int proc_write_foobar(struct file *file,  const char *buffer, unsigned long count,  void *data);

proc文件实际上是一个叫做proc_dir_entry的struct(定义在proc_fs.h),该struct中有int read_proc和int write_proc两个元素,要实现proc的文件的读写就要给这两个元素赋值。但这里不是简单地将一个整数赋值过去就行了,需要实现两个回调函数。在用户或应用程序访问该proc文件时,就会调用这个函数,实现这个函数时只需将想要让用户看到的内容放入page即可在用户或应用程序试图写入该proc文件时,就会调用这个函数,实现这个函数时需要接收用户写入的数据(buff参数)。

写回调函数

我们可以使用 write_proc 函数向 /proc 中写入一项。这个函数的原型如下:

int mod_write( struct file *filp, const char __user *buff,
               unsigned long len, void *data );

filp 参数实际上是一个打开文件结构(我们可以忽略这个参数)。buff 参数是传递给您的字符串数据。缓冲区地址实际上是一个用户空间的缓冲区,因此我们不能直接读取它。len 参数定义了在 buff 中有多少数据要被写入。data 参数是一个指向私有数据的指针。在这个模块中,我们声明了一个这种类型的函数来处理到达的数据。

Linux 提供了一组 API 来在用户空间和内核空间之间移动数据。对于 write_proc 的情况来说,我们使用了 copy_from_user 函数来维护用户空间的数据。

读回调函数

我们可以使用 read_proc 函数从一个 /proc 项中读取数据(从内核空间到用户空间)。这个函数的原型如下:

int mod_read( char *page, char **start, off_t off,
              int count, int *eof, void *data );

page 参数是这些数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常一页是 4KB)时,我们需要使用 start和 off 参数。当所有数据全部写入之后,就需要设置 eof(文件结束参数)。与 write 类似,data 表示的也是私有数据。此处提供的 page 缓冲区在内核空间中。因此,我们可以直接写入,而不用调用 copy_to_user


实例代码:

[cpp]  view plain  copy
  1. #include <linux/module.h>    
  2. #include <linux/kernel.h>    
  3. #include <linux/init.h>    
  4. #include <linux/proc_fs.h>    
  5. #include <linux/jiffies.h>    
  6. #include <asm/uaccess.h>    
  7.     
  8.     
  9. #define MODULE_VERS "1.0"    
  10. #define MODULE_NAME "procfs_example"    
  11.     
  12. #define FOOBAR_LEN 8    
  13.     
  14. struct fb_data_t {    
  15.     char name[FOOBAR_LEN + 1];    
  16.     char value[FOOBAR_LEN + 1];    
  17. };    
  18.     
  19.     
  20. static struct proc_dir_entry *example_dir, *foo_file;      
  21.     
  22. struct fb_data_t foo_data;    
  23.       
  24. static int proc_read_foobar(char *page, char **start,    
  25.                 off_t off, int count,     
  26.                 int *eof, void *data)    
  27. {    
  28.     int len;    
  29.     struct fb_data_t *fb_data = (struct fb_data_t *)data;    
  30.     
  31.     /* DON'T DO THAT - buffer overruns are bad */    
  32.     len = sprintf(page, "%s = '%s'\n",     
  33.               fb_data->name, fb_data->value);    
  34.     
  35.     return len;    
  36. }    
  37.     
  38.     
  39. static int proc_write_foobar(struct file *file,    
  40.                  const char *buffer,    
  41.                  unsigned long count,     
  42.                  void *data)    
  43. {    
  44.     int len;    
  45.     struct fb_data_t *fb_data = (struct fb_data_t *)data;    
  46.     
  47.     if(count > FOOBAR_LEN)    
  48.         len = FOOBAR_LEN;    
  49.     else    
  50.         len = count;    
  51.     
  52.     if(copy_from_user(fb_data->name, buffer, len))    
  53.         return -EFAULT;    
  54.     
  55.     fb_data->value[len] = '\0';    
  56.     
  57.     return len;    
  58. }    
  59.     
  60.     
  61. static int __init init_procfs_example(void)    
  62. {    
  63.     int rv = 0;    
  64.     
  65.     /* create directory */    
  66.     example_dir = proc_mkdir(MODULE_NAME, NULL);    
  67.     if(example_dir == NULL) {    
  68.         rv = -ENOMEM;    
  69.         goto out;    
  70.     }    
  71.     
  72.     /* create foo and bar files using same callback   
  73.      * functions    
  74.      */    
  75.     foo_file = create_proc_entry("foo", 0644, example_dir);    
  76.     if(foo_file == NULL) {    
  77.         rv = -ENOMEM;    
  78.         goto no_foo;    
  79.     }    
  80.     
  81.     strcpy(foo_data.name, "foo");    
  82.     strcpy(foo_data.value, "foo");    
  83.     foo_file->data = &foo_data;    
  84.     foo_file->read_proc = proc_read_foobar;    
  85.     foo_file->write_proc = proc_write_foobar;    
  86.            
  87.     /* everything OK */    
  88.     printk(KERN_INFO "%s %s initialised\n",    
  89.            MODULE_NAME, MODULE_VERS);    
  90.     return 0;    
  91.     
  92.    
  93. no_foo:    
  94.     remove_proc_entry("jiffies", example_dir);    
  95.    
  96. out:    
  97.     return rv;    
  98. }    
  99.     
  100.     
  101. static void __exit cleanup_procfs_example(void)    
  102. {    
  103.     
  104.     remove_proc_entry("foo", example_dir);      
  105.     remove_proc_entry(MODULE_NAME, NULL);    
  106.     
  107.     printk(KERN_INFO "%s %s removed\n",    
  108.            MODULE_NAME, MODULE_VERS);    
  109. }    
  110.     
  111.     
  112. module_init(init_procfs_example);    
  113. module_exit(cleanup_procfs_example);    
  114.     
  115. MODULE_AUTHOR("Erik Mouw");    
  116. MODULE_DESCRIPTION("procfs examples");    
  117. MODULE_LICENSE("GPL");    


linux设备驱动学习笔记--内核调试方法之proc:http://blog.csdn.net/itsenlin/article/details/43374921

添加一个新的自定义的系统调用:http://blog.csdn.net/daydring/article/details/23913525

猜你喜欢

转载自blog.csdn.net/zyc88888/article/details/80194088