-------------------------
在/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目录,找到占用我们目录的"坏进程"。
在我的系统上的输出:
代码:
[
[email protected]]/tmp# ./pcwd.sh
Usage: pcwd.sh path(absolute path)
[
[email protected]]/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
在我系统上的输出:
代码:
[
[email protected]]/tmp# ./pfile.sh
Usage: pfile.sh filename(absolute path)
[
[email protected]]/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中没有任何参数,你也可以扩展它的功能,使之能支持按照进程树状显示等等。
在我系统上的输出:
代码:
[
[email protected]]/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,可以显示进程的综合信息。输出分为四段,分别是进程状态(包含父子进程关系、进程信任状以及内存占用),执行环境(包含进程执行程序,命令行参数和环境变量),进程执行对象(包含进程执行体和引用的共享库),最后是进程打开的 所有文件。
代码:
[
[email protected]]/tmp# ./pstat.sh
Usage: pstat.sh PID
[
[email protected]]/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