Linux procfs详解
1.0 proc文件系统总览
在类Unix系统中体现了一种良好的抽象哲学,就是几乎所有的数据实体都被抽象成一个统一的接口--文件来看待,这样我们就可以用一些简单的基本工具完成大量复杂的操作。在Linux中存在着一类
特殊的伪文件系统,用于使用与文件接口统一的操作来完成各种功能,例如ptyfs、devfs、sysfs和procfs。而procfs就是其中应用最广泛的一种伪文件系统。
procfs是Linux内核信息的抽象文件接口,大量内核中的信息以及可调参数都被作为常规文件映射到一个目录树中,这样我们就可以简单直接的通过echo或cat这样的文件操作命令对系统信息进行查取
和调整了。同时procfs也提供了一个接口,使得我们自己的内核模块或用户态程序可以通过procfs进行参数的传递。在当今的Linux系统中,大量的系统工具也通过procfs获取内核参数,例如ps、
lspci等等,没有procfs它们将可能不能正常工作。
procfs的使用如同常规的文件系统一样,例如加载一个procfs (首先确定你的内核已经支持procfs默认如此):
# mount -t proc none /proc
也可以在/etc/fstab中加入如下一行使系统在启动时自动加载procfs(大多数系统中也是默认如此):
none /proc proc defaults 0 0
在proc文件系统中,主要包含三大类内容,进程相关部分,系统信息部分,以及系统子系统部分。在下面我们可以看到一个典型的procfs布局:
> ls /proc
1 2 2166 2281 cmdline interrupts meminfo stat
13 2001 2167 3 cpuinfo iomem misc swaps
1646 2042 2168 4 crypto ioports modules sys
1780 2058 2169 5 devices irq mounts sysrq-trigger
1834 2087 2170 6 dma isapnp mtrr sysvipc
1838 2096 2171 7 driver kcore net tty
1857 2107 2207 71 execdomains kmsg partitions uptime
1877 2117 2208 8 fb ksyms pci version
1889 2143 2216 9 filesystems loadavg scsi
1905 2153 2217 apm fs locks self
1960 2165 2219 bus ide mdstat slabinfo
在上面的布局中我们可以看到procfs包含的内容:
* 进程相关部分 (只读)
这部分文件都是以数字为名的子目录,这个数字就是相关进程的进程ID,在 1.1节中会详细介绍进程相关子目录的结构和信息。
需要注意的是procfs中进程子系统部分的一个特殊点,就是/proc/self,它是指向当前执行进程的符号连接,或者说--是指向未来你将要执行指令的心灵感应:
> cat self/cmdline
catself/cmdline
在这个命令中,我们希望它显示当前进程的cmdline参数,它恰恰就显示了当前进程--我们所执行的这条命令,cat self/cmdline。幸好这条指令显示出的信息会忽略空格,导致显示略微的不正常,否则我们倒是可以很容易的使用`cat self/cmdline`这样的命令制造出永远循环执行的进程来。;>
* 内核信息部分 (只读)
这部分文件同样处于/proc的顶层目录,不过它们大部分都是常规、只读的文本文件,可以直接用cat查看信息。作为系统内核执行体的抽象,我们也可以把它看作内核"进程"的信息部分,当然虽然并不存在这个进程实体。这里比较特别的一个文件是 /proc/cmdline :
>cat cmdline
ro root=/dev/hda2
在这个文件中存放的是系统内核引导时的命令行参数。此部分内容将在 1.3节中说明。
* 内核各子系统相关部分 (部分可调)
这部分是系统内核参数调整的重头戏,在procfs中,除去上面所述的两部分内容外,还有很大一部分信息文件被存放在了一些并非以数字命名的特殊目录中,这些目录下的信息就是内核各个重要子系统的信息和可调参数,主要有:
bus 总线信息(只读)
drivers 驱动信息(只读)
fs 文件系统特别信息(只读)
ide IDE接口信息(只读)
irq IRQ信息(只读)
net 网络子系统信息(只读)
scsi SCSI系统信息(只读)
sysvipc IPC子系统信息(只读)
tty tty子系统信息(只读)
sys 系统内核可调参数 (可调)
作为Linux系统内核参数的抽象文件接口,Linux内核的大部分默认可调参数都被放在了 /proc/sys目录下,这些参数都以常规文件的形式体现,并且可以用echo/cat等文件操作命令进行调整,调整的效果是即时的,并且在系统运行的整个生命周期之间都有效(知道再次改变它们或者系统重启)。
当然Linux也提供了另外一种途径sysctl来调整这些参数,sysctl是从BSD系统继承而来的一种系统参数动态调整方法,sysctl的使用更为简单,并且可以使用/etc/sysctl.conf保存配置以在下次启动时自动加载这些设置。对于sysctl可调参数体积调整方法将在另一篇文章中说明。
对于内核信息和参数的说明将在 1.4 - 1.7节中解释;对于/proc/sys中的可调参数将在第二章中详细说明。
1.1 进程相关子目录
在/proc目录中包含了一些以数字为名的子目录,这些目录就是系统当前运行进程的proc抽象。每一个目录都以相关联的活动系统进程PID为目录名,在目录下包含了一些文件,用于显示进程相关的信息。每个进程映射子目录的结构都如 Table 1-1.
..............................................................................
文件名 内容
cmdline 执行进程的命令行参数
cpu 在SMP系统中近程最后的执行CPU (2.4)(smp)
cwd 到当前工作目录的符号链接
environ 环境变量
exe 链接到进程对应的源可执行文件
fd 包含所有进程打开的文件描述符的子目录
maps 进程内存映射,包含进程执行空间以及动态链接库信息 (2.4)
mem 进程内存空间
root 连接到进程执行时的 / (root)目录
stat 进程状态
statm 进程内存状态信息
status 进程状态总览,包含进程名字、当前状态和各种信息统计
..............................................................................
举例来说,要获取一个进程的状态,只要读取下面进程PID子目录下的status文件 /proc/PID/status:
>cat /proc/self/status
Name: cat
State: R (running)
Pid: 5452
PPid: 743
TracerPid: 0 (2.4)
Uid: 501 501 501 501
Gid: 100 100 100 100
Groups: 100 14 16
VmSize: 1112 kB
VmLck: 0 kB
VmRSS: 348 kB
VmData: 24 kB
VmStk: 12 kB
VmExe: 8 kB
VmLib: 1044 kB
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 00000000fffffeff
CapPrm: 0000000000000000
CapEff: 0000000000000000
如同第一节所说,/proc/self连接指向读取它自身的进程映像,在之后一节的例子中都将以它作为我们的范例。
这条命令显示的信息与你通过 /bin/ps 命令获取到的进程信息基本相同,这恰巧是因为,ps也是通过读取procfs来获取这些信息的。statm 文件包含了更详细的进程内存状态,statm的详细内容按照数据项由左向右依次如 Table 1-2.
> cat /proc/self/statm
105 105 93 4 12 89 12
..............................................................................
数据项 内容
size 程序大小
resident 常驻内存空间大小
shared 共享内存页数
trs 代码段占用内存页数
drs 数据/堆栈段占用内存页数
lrs 引用库占用内存页数
dt 脏页数量
..............................................................................
1.2 内核数据
相似于进程入口,在/proc目录下的其他一些文件给出了内核信息数据,这些文件包含了系统当前运行内核相关信息。/proc目录下内核相关信息文件在Table 1-3 中列出,依赖于您的系统配置和加载的内核模块,在您的系统中的显示可能会略有不同。
..............................................................................
文件 内容
apm 高级电源管理信息
bus bus总线相关信息
cmdline 内核引导命令行参数
cpuinfo cpu信息
devices 当前可用设备 (包含所有块设备和字符设备)
dma DMA通道使用状况
filesystems 当前内核支持的文件系统
driver 驱动相关信息 (2.4)
execdomains 安全相关的Execdomains信息 (2.4)
fb Frame Buffer 设备 (2.4)
fs 本地文件系统参数 (2.4)
ide IDE子系统相关信息的子目录
interrupts 中断使用状况
iomem 内存映射图 (2.4)
ioports I/O端口使用状况
irq 关联到cpu的irq使用状况 (2.4)(smp?)
isapnp ISA PnP (即插即用) 信息 (2.4)
kcore Kernel core image,内核转储映像 (2.4)
kmsg Kernel messages
ksyms Kernel symbol table,内核符号表
loadavg 最后1、5 、15 分钟的平均负载
locks Kernel locks, 内核锁信息
meminfo 内存信息
misc 内核信息杂项
modules 已加载内核模块列表
mounts 已加载的文件系统
net 网络子系统信息
partitions 已识别的本地系统分区表
pci PCI总线相关信息,在新版本中指向 /proc/bus/pci/ 目录 (2.4)
rtc rtc实时钟
scsi SCSI 总线信息
slabinfo Slab 内存分配池信息
stat 内核状态总览
swaps Swap 空间状态
sys 内核系统参数 (参见第二章)
sysvipc SysVIPC 资源状态 (msg, sem, shm) (2.4)
tty TTY驱动信息
uptime 系统 uptime
version 内核版本
video video 资源状态 (2.4)
..............................................................................
在proc文件系统中大多数文件都是可读的文本,可以直接使用系统中的常规文件处理命令进行操作。当然,这也依赖于目标文件的权限属性。例如要查看系统中断信息 /proc/interrupts:
> cat /proc/interrupts
CPU0
0: 8728810 XT-PIC timer
1: 895 XT-PIC keyboard
2: 0 XT-PIC cascade
3: 531695 XT-PIC aha152x
4: 2014133 XT-PIC serial
5: 44401 XT-PIC pcnet_cs
8: 2 XT-PIC rtc
11: 8 XT-PIC i82365
12: 182918 XT-PIC PS/2 Mouse
13: 1 XT-PIC fpu
14: 1232265 XT-PIC ide0
15: 7 XT-PIC ide1
NMI: 0
在2.4版内核中,当使用了SMP时这个文件末尾会多出两行SMP相关属性 LOC & ERR :
> cat /proc/interrupts
CPU0 CPU1
0: 1243498 1214548 IO-APIC-edge timer
1: 8949 8958 IO-APIC-edge keyboard
2: 0 0 XT-PIC cascade
5: 11286 10161 IO-APIC-edge soundblaster
8: 1 0 IO-APIC-edge rtc
9: 27422 27407 IO-APIC-edge 3c503
12: 113645 113873 IO-APIC-edge PS/2 Mouse
13: 0 0 XT-PIC fpu
14: 22491 24012 IO-APIC-edge ide0
15: 2183 2415 IO-APIC-edge ide1
17: 30564 30414 IO-APIC-level eth0
18: 177 164 IO-APIC-level bttv
NMI: 2457961 2457959
LOC: 2457882 2457881
ERR: 2155
NMI是每个CPU上产生的不可屏蔽中断(Non Maskable Interrupt)的计数;
LOC是每个CPU上APIC本地中断的计数。
ERR是SMP系统中IO-APIC总线失败错误的计数,如果这个数量太高,可能你的内核运行会有问题,这时候就需要测试内核,查看硬件和APIC是否有兼容性问题。
在2.4内核中irq相关的内核信息被放在/proc/irq目录下,在这个目录下包含一个文件
prof_cpu_mask和每个IRQ独属的一个子目录。
> ls /proc/irq/
0 10 12 14 16 18 2 4 6 8 prof_cpu_mask
1 11 13 15 17 19 3 5 7 9
> ls /proc/irq/0/
smp_affinity
2.4内核中可以使用IRQ绑定属性,是某个或全部的IRQ挂接到SMP集合中的某个CPU上,这个特性可以通过prof_cpu_mask和smp_affinity来调整。在默认情况下这两个文件的内容都"ffffffff",作为一个位映射而存在,你可以使用echo命令来指定一个CPU处理IRQ事件。
> cat /proc/irq/0/smp_affinity
ffffffff
> echo 1 > /proc/irq/prof_cpu_mask
这天命令的结果就是系统中只有第一个CPU可以捕获IRQ事件,如果您使用的是"echo 5"的话那么第一和第四个CPU都可以捕获和处理事件(1 + 4)。
在默认情况下IRQ事件由IO-APIC分配,它将轮询每个配置中的CPU,等待其中一个处理事件响应。
在slabinfo文件文件中我们可以看到Linux内核的内存分配池信息,2.4版本内核中使用slab算法来为内核对象(网络缓存、目录高速缓存以及文件分配表等等)分配内存页。
在/proc目录下还有三个重要的目录: net,scsi和sys,我们会在后面的章节中陆续描述;此外如果您的系统中没有SCSI设备(或没有SCSI驱动)的话,/proc/scsi目录是不存在的。
1.3 IDE设备 /proc/ide
/proc/ide目录下包含了所有内核识别出的IDE设备的信息。在/proc/ide目录下包含drivers文件和若干个以IDE设备名或IDE控制器名为名的子目录。
> ls -alF /proc/ide/
total 3
dr-xr-xr-x 4 root root 0 10月 9 23:36 ./
dr-xr-xr-x 54 root root 0 2004-10-10 ../
-r--r--r-- 1 root root 0 10月 9 23:36 drivers
lrwxrwxrwx 1 root root 8 10月 9 23:36 hda -> ide0/hda/
lrwxrwxrwx 1 root root 8 10月 9 23:36 hdb -> ide0/hdb/
lrwxrwxrwx 1 root root 8 10月 9 23:36 hdc -> ide1/hdc/
dr-xr-xr-x 4 root root 0 10月 9 23:36 ide0/
dr-xr-xr-x 3 root root 0 10月 9 23:36 ide1/
-r--r--r-- 1 root root 0 10月 9 23:36 piix
drivers文件包含了当前加载的IDE设备驱动:
> cat /proc/ide/drivers
ide-floppy version 0.99.newide
ide-disk version 1.17
ide-default version 0.9.newide
在/proc/ide目录下还可以看到其他一些以设备命名的目录,在这些目录下我们可以看到更详细的信息。piix是IDE控制芯片组的名字,在你的系统中可能是其他名字。此外还包含若干个(一般的PC上是2个)IDE控制器为名的目录,以及以IDE终端设备名命名的快捷方式,它门将链接到控制器目录下对应的设备文件上。
在ide*目录中我们可以得到更多的信息,如 Table 1-4.
..............................................................................
文件名 内容
channel IDE通道 (0 or 1)
config 配置 (only for PCI/IDE bridge)
mate Mate name
model IDE控制器的类型/芯片组
hd? IDE总线上连接的可用设备
..............................................................................
当前连接在控制器上的每个设备也将成为一个单独的子目录,如 Table 1-5.
..............................................................................
文件名 内容
cache 设备缓存大小
capacity 设备数据块数量 (按 512Byte 块)
driver 驱动和版本
geometry 物理和逻辑的设备参数
identify 设备标示块
media 媒体类型
model 设备标识符(型号或名字)
settings 设备配置参数
smart_thresholds IDE disk management thresholds
smart_values IDE disk management values
..............................................................................
在这里比较有用的信息是settings文件,它包含了一个驱动器相关的信息总览:
# cat /proc/ide/ide0/hda/settings
name value min max mode
---- ----- --- --- ----
bios_cyl 526 0 65535 rw
bios_head 255 0 255 rw
bios_sect 63 0 63 rw
breada_readahead 4 0 127 rw
bswap 0 0 1 r
file_readahead 72 0 2097151 rw
io_32bit 0 0 3 rw
keepsettings 0 0 1 rw
max_kb_per_request 122 1 127 rw
multcount 0 0 8 rw
nice1 1 0 1 rw
nowerr 0 0 1 rw
pio_mode write-only 0 255 w
slow 0 0 1 rw
unmaskirq 0 0 1 rw
using_dma 0 0 1 rw
1.4 网络信息 /proc/net
/proc/net 子目录包含了系统中网络相关的内核统计信息和视图,常规的文件列表如Table 1-7 中说明; 如果你的内核支持IPV6,那么还有一些IPV6相关信息在 Table 1-6中
..............................................................................
文件名 内容
udp6 UDP sockets (IPv6)
tcp6 TCP sockets (IPv6)
raw6 Raw 设备状态 (IPv6)
igmp6 系统当前加入的IP多播地址 (IPv6)
if_inet6 IPv6 网络接口地址列表
ipv6_route IPv6 内核路由表
rt6_stats IPv6 全局路由表状态
sockstat6 Socket 状态 (IPv6)
snmp6 Snmp 数据 (IPv6)
..............................................................................
..............................................................................
文件名 内容
arp 内核 ARP 表
atm atm设备接口信息
drivers 加载的驱动模块信息
dev 网络设备以及状态
dev_mcast 二层多播组以及监听设备信息
(包含interface index, label, number of references, number of
bound addresses).
dev_stat 网络设备状态
ip_fwchains ipchains 防火墙规则链 (2.2)
ip_fwnames ipchains 防火墙规则链名 (2.2)
ip_masq 包含IP伪装映射表的目录 (2.2)
ip_masquerade 主IP伪装映射表 (2.2)
netstat 网络状态
raw 原始设备状态
route 内核路由表
rpc 包含rpc信息的目录
rt_cache 路由cache
snmp SNMP 数据
sockstat Socket 状态
tcp TCP sockets
tr_rif Token ring RIF 令牌环网路由表
udp UDP sockets
unix UNIX domain sockets
wireless Wireless 接口数据 (Wavelan etc)
igmp 主机当前加入的IP多播组地址
psched 全局数据包调度参数
netlink PF_NETLINK sockets 列表
ip_mr_vifs 多播虚拟地址列表
ip_mr_cache 多播路由cache列表
..............................................................................
由于2.4之后的内核引入了netfilter/iptables防火墙,因此在防火墙部分的信息与2.2略有不同:
..............................................................................
文件名 内容
ip_tables_matches iptables支持的过滤模式
ip_tables_names iptables规则表名字
ip_tables_targets iptables规则链目标
ip_conntrack iptables状态检测跟踪表
..............................................................................
您可以使用这些信息来查看当前系统中可用的网络设备,以及这些设备上通过的流量和路由信息:
> cat /proc/net/dev
Inter-|Receive |[...
face |bytes packets errs drop fifo frame compressed multicast|[...
lo: 908188 5596 0 0 0 0 0 0 [...
ppp0:15475140 20721 410 0 0 410 0 0 [...
eth0: 614530 7085 0 0 0 0 0 1 [...
...] Transmit
...] bytes packets errs drop fifo colls carrier compressed
...] 908188 5596 0 0 0 0 0 0
...] 1375103 17405 0 0 0 0 0 0
...] 1703981 5535 0 0 0 3 0 0
如果系统中使用了Ethernet Channel特性,使若干个物理接口绑定为一个逻辑设备的话,这个逻辑设备将会拥有一个以设备名命名的子目录,其中包含一些bond模块相关的特殊信息。例如把eth0和eth1绑定为设备 bond0 ,那么可以在 /proc/net/bond0/目录下看到bond的特殊信息,例如主从接口、链路状态等等。
1.5 SCSI 设备信息
如果你的系统中含有任何SCSI设备,那么在 /proc/scsi 目录下可以看到系统识别到的SCSI设备相关信息:
>cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
Vendor: IBM Model: DGHS09U Rev: 03E0
Type: Direct-Access ANSI SCSI revision: 03
Host: scsi0 Channel: 00 Id: 06 Lun: 00
Vendor: PIONEER Model: CD-ROM DR-U06S Rev: 1.04
Type: CD-ROM ANSI SCSI revision: 02
系统中的SCSI设备将映射到/proc/scsi目录下形成一个子树,按照对应的设备模块和设备总线号可以查看相应设备的参数信息,例如一个Adaptec AHA-2940 SCSI 适配器:
> cat /proc/scsi/aic7xxx/0
Adaptec AIC7xxx driver version: 5.1.19/3.2.4
Compile Options:
TCQ Enabled By Default : Disabled
AIC7XXX_PROC_STATS : Disabled
AIC7XXX_RESET_DELAY : 5
Adapter Configuration:
SCSI Adapter: Adaptec AHA-294X Ultra SCSI host adapter
Ultra Wide Controller
PCI MMAPed I/O Base: 0xeb001000
Adapter SEEPROM Config: SEEPROM found and used.
Adaptec SCSI BIOS: Enabled
IRQ: 10
SCBs: Active 0, Max Active 2,
Allocated 15, HW 16, Page 255
Interrupts: 160328
BIOS Control Word: 0x18b6
Adapter Control Word: 0x005b
Extended Translation: Enabled
Disconnect Enable Flags: 0xffff
Ultra Enable Flags: 0x0001
Tag Queue Enable Flags: 0x0000
Ordered Queue Tag Flags: 0x0000
Default Tag Queue Depth: 8
Tagged Queue By Device array for aic7xxx host instance 0:
{255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}
Actual queue depth per device for aic7xxx host instance 0:
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
Statistics:
(scsi0:0:0:0)
Device using Wide/Sync transfers at 40.0 MByte/sec, offset 8
Transinfo settings: current(12/8/1/0), goal(12/8/1/0), user(12/15/1/0)
Total transfers 160151 (74577 reads and 85574 writes)
(scsi0:0:6:0)
Device using Narrow/Sync transfers at 5.0 MByte/sec, offset 15
Transinfo settings: current(50/15/0/0), goal(50/15/0/0), user(50/15/0/0)
Total transfers 0 (0 reads and 0 writes)
1.6 并口信息 /proc/parport
/proc/parport 包含系统并口信息,按照并口端口号(0,1,2,...)每个设备将映射到一个子目录中。在这个目录下包含的信息如 Table 1-8.
..............................................................................
文件名 内容
autoprobe IEEE-1284 标准兼容的设备ID信息
devices 端口使用的设备驱动列表
hardware 端口使用的base address, IRQ line 和 DMA channel.
irq 端口使用的IRQ号,你可以写入一个新值指定IRQ号 (IRQ number or none).
..............................................................................
1.7 TTY信息 /proc/tty
-------------------------
在/proc/tty目录中包含了系统中当前在用的tty及其信息,在这个目录中也可以找到设备
信息和线路disciplines,如 Table 1-9.
Table 1-9: /proc/tty 中的文件
..............................................................................
文件名 内容
drivers 设备及引用计数
ldiscs registered line disciplines
driver/serial tty线路状态
..............................................................................
要查看系统中的当前在用ttys,可以简单的查看 /proc/tty/drivers:
> cat /proc/tty/drivers
pty_slave /dev/pts 136 0-255 pty:slave
pty_master /dev/ptm 128 0-255 pty:master
pty_slave /dev/ttyp 3 0-255 pty:slave
pty_master /dev/pty 2 0-255 pty:master
serial /dev/cua 5 64-67 serial:callout
serial /dev/ttyS 4 64-67 serial
/dev/tty0 /dev/tty0 4 0 system:vtmaster
/dev/ptmx /dev/ptmx 5 2 system
/dev/console /dev/console 5 1 system:console
/dev/tty /dev/tty 5 0 system:/dev/tty
unknown /dev/tty 4 1-63 console
本章介绍了 /proc 文件系统提供的系统运行时信息. 在 /proc 文件系统中,您不仅可以简单直接的访问进程相关信息,也可以通过它查看各个方面的系统内核状态。
在 /proc 文件系统中,大部分信息都以常规或文本文件的形式反映出来,您可以任意使用简单的文件处理命令来查看它(只要权限允许);如果某些文件不能被查看或者产生乱码,那么它可能是一些特殊类型的文件,需要其它手段来处理,例如 /proc/kcore 可以通过gdb等内核调试工具来查看,而其他一些数据则可以被ps、top等工具所理解。
在这一章中,我们对procfs的结构进行了一下纵览,对它的作用也该有一些了解了。在procfs中除了得到大量系统内核信息之外,它最重要的一个作用莫过于对进程的监控和分析了。有了procfs,你也可以写出自己的ps/top来,甚至不用任何编程工具......
比如,很多Linux新手都常常遇到的一个问题,就是夹在了一个文件系统之后不能卸载,系统报告这样的错误:
代码:
# umount /db1
umount: /db1: device is busy
经验老到的管理员们都知道,这个问题是由于某些进程的工作目录还在这个目录下,导致系统卷忙而无法卸载,只要杀掉那个进程,文件系统就可以正常卸载了。但究竟是哪个进程还在那里呢?找起来恐怕也要费半天神。虽然有pfile和lsof之类的工具可用,但总 也有应急的时候吧,这棵小脚本就可以为你解忧。
代码:
#!/bin/bash
#pcwd.sh,查找系统中工作在目标路径下的进程,使用方法: pcwd.sh 路径名
test $1 || { echo "Usage: pcwd.sh path(absolute path)" && exit };
PS=`ls /proc/*[0-9]*|grep :` ;
PSList=`echo $PS |tr -d '/proc'|tr -d ':'`;
for PID in $PSList
do
test -e /proc/$PID && (ls -alF /proc/$PID/cwd|grep $1 >/dev/null ) && echo "Process $PID (`cat /proc/$PID/status |grep Name |tr -d 'Name: '`) is work in $1 ";
done
就是这样短短的几行代码,甚至不用任何的临时文件,我们就获取了执行命令前的当前系统进程表映像,然后遍历每个进程的proc目录,找到占用我们目录的"坏进程"。
在我的系统上的输出:
代码:
[elly@frost.llnl]/tmp# ./pcwd.sh
Usage: pcwd.sh path(absolute path)
[elly@frost.llnl]/tmp# ./pcwd.sh /usr
Process 1283 (vi) is work in /usr ;
Process 3113 (bsh) is work in /usr ;
在上面的例子中,我们只用了最简单的四五个文件和文本处理命令,就完成了这个小程序,你甚至可以把所有的语句写在一行上,通过命令行或alias定义就完成这个功能。
把它稍稍修改一下就是另外一个功能,查找正在使用某个文件的进程:
代码:
#!/bin/bash
test $1 || { echo "Usage: pfile.sh filename(absolute path)" && exit };
PS=`ls /proc/*[0-9]*|grep :` ;
PSList=`echo $PS |tr -d '/proc'|tr -d ':'`;
for PID in $PSList
do
test -e /proc/$PID && (ls -alF /proc/$PID/fd|grep $1 >/dev/null ) && echo "Process $PID (`cat /proc/$PID/status |grep Name |tr -d 'Name: '`) is openning $1;";
done
在我系统上的输出:
代码:
[elly@frost.llnl]/tmp# ./pfile.sh
Usage: pfile.sh filename(absolute path)
[elly@frost.llnl]/tmp# ./pfile.sh access_log
Process 109 (httpd) is openning access_log;
Process 110 (httpd) is openning access_log;
Process 112 (httpd) is openning access_log;
Process 113 (httpd) is openning access_log;
Process 116 (httpd) is openning access_log;
Process 99 (httpd) is openning access_log;
目标文件名可以使用相对或绝对路径,甚至可以只输入半个文件名...当然路径越精确查找的结果也越准确。在这个例子中,很容易就可以扩展它的功能,让它实现类似lsof的功能,可以列举系统中所有正在被使用的文件。好啦,我们做一个有用点的程序。
ps,每台机器上都有吧。不幸的是,在某些极端环境下,系统中的PS是不可靠的,比如,坏了...或被人替换了。
很多恶意的黑客入侵系统之后会在系统上安装一类叫rootkit的后门包,用来替换系统中ps、netstat等重要程序以隐藏自己的痕迹,这个时候一般比较稳妥的办法是自己上传一份可靠的系统工具包,或者静态编译的工具包。当然,也可以用这个土办法,直 接从procfs里读取信息。(如果是比较高明的黑客,使用LKM等内核后门那这个就没有用了哦)
范例:懒人的ps,就叫它lps吧。
代码:
#!/bin/bash
PS=`ls /proc/*[0-9]*|grep :` ;
PSList=`echo $PS |tr -d '/proc' |tr -d ':' |sort `;
echo -e "PID PPID UID GID STAT MEM TTY CMD"
for PID in $PSList
do
test -e /proc/$PID && sPID=`cat /proc/$PID/status |grep ^Pid: |awk '{print $2}'`
&& sPPID=`cat /proc/$PID/status |grep ^PPid: |awk '{print $2}'`
&& sTTY=`ls -alF /proc/$PID/fd |grep /dev/ |awk '{print $11}' |grep ty |head -n 1`
&& sUID=`cat /proc/$PID/status |grep ^Uid: |awk '{print $2}'`
&& sGID=`cat /proc/$PID/status |grep ^Gid: |awk '{print $2}'`
&& sSTAT=`cat /proc/$PID/status |grep ^State: |awk '{print $2 $3}'`
&& sMEM=`cat /proc/$PID/status |grep ^VmSize: |awk '{print $2 $3}'`
&& if [ -e /proc/$PID/exe ]
then
sCMD=`ls -alF /proc/$PID/exe |awk '{print $11}' |tr -d '$*' `
else
sCMD=`cat /proc/$PID/status |grep ^Name: |awk '{print $2}'`
sCMD="[ $sCMD ]"
fi
echo -e "$sPID $sPPID $sUID $sGID $sSTAT $sMEM $sTTY $sCMD"
done
简要介绍,这个lps或列举系统中自身进程(lps)之外的所有进程,然后读取和显示他们的八项属性,依次是:进程ID(PID) 父进程ID(PPID) 属主UID(UID) 属主GID(GID) 当前状态 占用内存 运行终端 完全执行路径。
在显示格式参考了Linux标准ps输出的一部分,例如某些系统线程没有可执行文件的,就会显示他们的内核名字,例如[ ksoftirqd_CPU0 ] 。
懒人的PS中没有任何参数,你也可以扩展它的功能,使之能支持按照进程树状显示等等。
在我系统上的输出:
代码:
[elly@frost.llnl]/tmp# ./lps.sh
PID PPID UID GID STAT MEM TTY CMD
1 0 0 0 S(sleeping) 1116kB /sbin/init
101 1 0 0 S(sleeping) 2168kB /usr/local/sbin/sshd
109 99 99 99 S(sleeping) 6100kB /usr/local/apache/bin/httpd
110 99 99 99 S(sleeping) 6100kB /usr/local/apache/bin/httpd
112 99 99 99 S(sleeping) 6100kB /usr/local/apache/bin/httpd
113 99 99 99 S(sleeping) 6100kB /usr/local/apache/bin/httpd
116 99 99 99 S(sleeping) 6100kB /usr/local/apache/bin/httpd
118 1 0 0 S(sleeping) 1656kB /bin/bash
119 1 0 0 S(sleeping) 1648kB /bin/bash
120 1 0 0 S(sleeping) 1648kB /bin/bash
128 1 0 0 S(sleeping) 2224kB /dev/tty1 /bin/login
1283 3113 0 0 S(sleeping) 1512kB /dev/ttyp0 /bin/vi
129 1 0 0 S(sleeping) 1136kB /dev/tty2 /sbin/getty
130 1 0 0 S(sleeping) 1136kB /dev/tty3 /sbin/getty
131 1 0 0 S(sleeping) 1136kB /dev/tty4 /sbin/getty
135 1 0 0 S(sleeping) 1136kB /dev/tty5 /sbin/getty
136 1 0 0 S(sleeping) 1136kB /dev/tty6 /sbin/getty
137 1 0 0 S(sleeping) 1140kB /dev/ttyS0 /sbin/getty
15329 3112 0 0 S(sleeping) 1792kB /dev/ttyp1 /bin/bash
2 1 0 0 S(sleeping) [ keventd ]
256 128 0 0 S(sleeping) 1712kB /dev/tty1 /bin/bash
3 1 0 0 S(sleeping) [ ksoftirqd_CPU0 ]
3112 101 0 0 S(sleeping) 2452kB /dev/ptyp1 /usr/local/sbin/sshd
3113 3112 0 0 S(sleeping) 1728kB /dev/ttyp0 /bin/bash
3872 120 0 0 S(sleeping) 1084kB /bin/sleep
4 1 0 0 S(sleeping) [ kswapd ]
4 1 0 0 S(sleeping) [ kswapd ]
4 1 0 0 S(sleeping) [ kswapd ]
4089 15329 0 0 S(sleeping) 1664kB /dev/ttyp1 /bin/bash
4089 15329 0 0 S(sleeping) 1664kB /dev/ttyp1 /bin/bash
5 1 0 0 S(sleeping) [ bdflush ]
6 1 0 0 S(sleeping) [ kupdated ]
99 1 0 0 S(sleeping) 6016kB /usr/local/apache/bin/httpd
Solaris上有/usr/proc/bin工具集,里面的ptree和pmap很是好用,甚至比本来的ps还好:P可惜Linux上是没有的,现在你可以自己写一个,用来综合显示更多的进程状态。
代码:
#!/bin/bash
#PROC=`mount |grep 'type proc'|awk '{print $3}'`
test $1 || { echo "Usage: pstat.sh PID" && exit };
PID=$1;
echo "Process $1 Status...";
echo "......................";
echo
cat /proc/$PID/status|grep ^Name:
cat /proc/$PID/status|grep ^Pid:
cat /proc/$PID/status|grep ^PPid:
cat /proc/$PID/status|grep ^Uid:
cat /proc/$PID/status|grep ^Gid:
cat /proc/$PID/status|grep ^State:
cat /proc/$PID/status|grep ^VmSize:
echo
CMD=`ls -alF /proc/$PID/exe |awk '{print $11}' |tr -d '$*'`;echo "Command path: $CMD";
ARG=`cat /proc/$PID/cmdline`;echo "Command line: $ARG";
CWD=`ls -alF /proc/$PID/cwd |awk '{print $11}'`;echo "CWD: $CWD";
echo
ENVI=`cat /proc/$PID/environ`;echo "ENVIRON: $ENVI";
echo
echo
echo "Process shared object:";
echo "......................";
cat /proc/$PID/maps |grep $CMD |grep xp;
cat /proc/$PID/maps |grep .so |grep xp;
echo
echo
echo "Process used file:";
echo "......................";
ls -alF /proc/$PID/fd |grep '->' |awk '{print $11}' |sort |uniq -c |sort -rn ;
echo
这个程序叫pstat.sh,可以显示进程的综合信息。输出分为四段,分别是进程状态(包含父子进程关系、进程信任状以及内存占用),执行环境(包含进程执行程序,命令行参数和环境变量),进程执行对象(包含进程执行体和引用的共享库),最后是进程打开的 所有文件。
代码:
[elly@frost.llnl]/tmp# ./pstat.sh
Usage: pstat.sh PID
[elly@frost.llnl]/tmp# ./pstat.sh 7238
Process 7238 Status...
......................
Name: vi
Pid: 7238
PPid: 3113
Uid: 0 0 0 0
Gid: 0 0 0 0
State: S (sleeping)
VmSize: 1648 kB
Command path: /bin/vi
Command line: vi
CWD: /usr/
ENVIRON: USERNAME=root
Process shared object:
......................
08048000-08098000 r-xp 00000000 03:01 3891 /bin/vi
40000000-40013000 r-xp 00000000 03:01 3942 /lib/ld-2.1.3.so
40016000-40019000 r-xp 00000000 03:01 4002 /lib/libtermcap.so.2.0.8
4001a000-40107000 r-xp 00000000 03:01 3949 /lib/libc-2.1.3.so
4010f000-40117000 r-xp 00000000 03:01 3981 /lib/libnss_files-2.1.3.so
Process used file:
......................
/dev/ttyp0
/etc/motd
转http://luckyclouds.iteye.com/blog/675711