一个程序被加载到内存当中运行,那么在内存内的那个数据就被称为程序(process)。程序是操作系统上非常重要的概念,所有系统上面跑的数据都会以程序的型态存在。那么系统的程序有哪些状态?不同的状态会如何影响系统的运行?程序之间是否可以互相控管等等的,这些都是我们所必须要知道的项目。另外与程序有关的还有 SELinux 这个加强文件存取安全性的咚咚,也必须要做个了解呢! |
由前面一连几个章节的数据看来,我们一直强调在 Linux 底下所有的命令与你能够进行的动作都与权限有关,而系统如何判定你的权限呢?当然就是第十四章帐号管理当中提到的 UID/GID 的相关概念,以及文件的属性相关性罗!再进一步来解释,你现在大概知道,在 Linux 系统当中:『触发任何一个事件时,系统都会将他定义成为一个程序,并且给予这个程序一个 ID ,称为 PID,同时依据启发这个程序的使用者与相关属性关系,给予这个 PID 一组有效的权限配置。』从此以后,这个 PID 能够在系统上面进行的动作,就与这个 PID 的权限有关了!
看这个定义似乎没有什么很奇怪的地方,不过,您得要了解什么叫做『触发事件』才行啊!我们在什么情况下会触发一个事件?而同一个事件可否被触发多次?呵呵!来了解了解先!
我们如何产生一个程序呢?其实很简单啦,就是『运行一个程序或命令』就可以触发一个事件而取得一个 PID 罗!我们说过,系统应该是仅认识 binary file 的,那么当我们要让系统工作的时候,当然就是需要启动一个 binary file 罗,那个 binary file 就是程序 (program) 啦!
那我们知道,每个程序都有三组人马的权限,每组人马都具有 r/w/x 的权限,所以:『不同的使用者身份运行这个 program 时,系统给予的权限也都不相同!』举例来说,我们可以利用 touch 来创建一个空的文件,当 root 运行这个 touch 命令时,他取得的是 UID/GID = 0/0 的权限,而当 dmtsai (UID/GID=501/501) 运行这个 touch 时,他的权限就跟 root 不同啦!我们将这个概念绘制成图示来瞧瞧如下:
如上图所示,程序一般是放置在实体磁碟中,然后透过使用者的运行来触发。触发后会加载到内存中成为一个个体,那就是程序。为了操作系统可管理这个程序,因此程序有给予运行者的权限/属性等参数,并包括程序所需要的命令码与数据或文件数据等,最后再给予一个 PID 。系统就是透过这个 PID 来判断该 process 是否具有权限进行工作的!他是很重要的哩!
举个更常见的例子,我们要操作系统的时候,通常是利用连线程序或者直接在主机前面登陆,然后取得我们的 shell 对吧!那么,我们的 shell 是 bash 对吧,这个 bash 在 /bin/bash 对吧,那么同时间的每个人登陆都是运行 /bin/bash 对吧!不过,每个人取得的权限就是不同!也就是说,我们可以这样看:
也就是说,当我们登陆并运行 bash 时,系统已经给我们一个 PID 了,这个 PID 就是依据登陆者的 UID/GID (/etc/passwd) 来的啦~以上面的图 1.1.2 配合图 1.1.1 来做说明的话,我们知道 /bin/bash 是一个程序 (program),当 dmtsai登陆后,他取得一个 PID 号码为 2234 的程序,这个程序的 User/Group 都是 dmtsai,而当这个程序进行其他作业时,例如上面提到的 touch 这个命令时,那么由这个程序衍生出来的其他程序在一般状态下,也会沿用这个程序的相关权限的!
让我们将程序与程序作个总结:
在上面的说明里面,我们有提到所谓的『衍生出来的程序』,那是个啥咚咚?这样说好了,当我们登陆系统后,会取得一个 bash 的 shell ,然后,我们用这个 bash 提供的介面去运行另一个命令,例如 /usr/bin/passwd 或者是 touch 等等,那些另外运行的命令也会被触发成为 PID ,呵呵!那个后来运行命令才产生的 PID 就是『子程序』了,而在我们原本的 bash 环境下,就称为『父程序』了!借用我们在 十一章 Bash 谈到的 export所用的图示好了:
所以你必须要知道,程序彼此之间是有相关性的!以上面的图示来看,连续运行两个 bash 后,第二个 bash 的父程序就是前一个 bash。因为每个程序都有一个 PID ,那某个程序的父程序该如何判断?就透过 Parent PID (PPID) 来判断即可。此外,由十一章的 export 内容我们也探讨过环境变量的继承问题,子程序可以取得父程序的环境变量啦!让我们来进行底下的练习,以了解什么是子程序/父程序。
例题:
请在目前的 bash 环境下,再触发一次 bash ,并以『 ps -l 』这个命令观察程序相关的输出资讯。
答:
直接运行 bash ,会进入到子程序的环境中,然后输入 ps -l 后,出现:
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 8074 8072 2 76 0 - 1287 wait pts/1 00:00:00 bash 0 S 0 8102 8074 4 76 0 - 1287 wait pts/1 00:00:00 bash 4 R 0 8118 8102 0 78 0 - 1101 - pts/1 00:00:00 ps有看到那个 PID 与 PPID 吗?第一个 bash 的 PID 与第二个 bash 的 PPID 都是 8074 啊,因为第二个 bash 是来自於第一个所产生的嘛!另外,每部主机的程序启动状态都不一样,所以在你的系统上面看到的 PID 与我这里的显示一定不同!那是正常的!详细的 ps 命令我们会在本章稍后介绍,这里你只要知道 ps -l 可以查阅到相关的程序资讯即可。 |
很多朋友常常会发现:『咦!明明我将有问题的程序关闭了,怎么过一阵子他又自动的产生?而且新产生的那个程序的 PID 与原先的还不一样,这是怎么回事呢?』不要怀疑,如果不是crontab 工作排程的影响,肯定有一支父程序存在,所以你杀掉子程序后,父程序就会主动再生一支!那怎么办?正所谓这:『擒贼先擒王』,找出那支父程序,然后将他删除就对啦!
其实子程序与父程序之间的关系还挺复杂的,最大的复杂点在於程序互相之间的呼叫。在 Linux 的程序呼叫通常称为 fork-and-exec 的流程 (注1)!程序都会藉由父程序以复制 (fork) 的方式产生一个一模一样的子程序,然后被复制出来的子程序再以 exec 的方式来运行实际要进行的程序,最终就成为一个子程序的存在。整个流程有点像底下这张图:
(1)系统先以 fork 的方式复制一个与父程序相同的缓存程序,这个程序与父程序唯一的差别就是 PID 不同!但是这个缓存程序还会多一个 PPID 的参数,PPID 如前所述,就是父程序的程序识别码啦!然后(2)缓存程序开始以 exec的方式加载实际要运行的程序,以上述图示来讲,新的程序名称为 qqq ,最终子程序的程序码就会变成 qqq 了!这样了解乎!
如果就我们之前学到的一些命令数据来看,其实我们下达的命令都很简单,包括用 ls 显示文件啊、用 touch 创建文件啊、rm/mkdir/cp/mv 等命令管理文件啊、chmod/chown/passwd 等等的命令来管理权限等等的,不过,这些命令都是运行完就结束了。也就是说,该项命令被触发后所产生的 PID 很快就会终止呢!那有没有一直在运行的程序啊?当然有啊!而且多的是呢!
举个简单的例子来说好了,我们知道系统每分钟都会去扫瞄 /etc/crontab 以及相关的配置档,来进行工作排程吧?那么那个工作排程是谁负责的?当然不是鸟哥啊!呵呵!是 crond 这个程序所管理的,我们将他启动在背景当中一直持续不断的运行,套句以前 DOS 年代常常说的一句话,那就是『常驻在内存当中的程序』啦!
常驻在内存当中的程序通常都是负责一些系统所提供的功能以服务使用者各项任务,因此这些常驻程序就会被我们称为:服务 (daemon)。系统的服务非常的多,不过主要大致分成系统本身所需要的服务,例如刚刚提到的 crond 及 atd ,还有 syslog 等等的。还有一些则是负责网络连线的服务,例如 Apache, named, postfix, vsftpd... 等等的。这些网络服务比较有趣的地方,在於这些程序被运行后,他会启动一个可以负责网络监听的端口 (port) ,以提供外部用户端 (client) 的连线要求。
我们现在知道了,其实在 Linux 底下运行一个命令时,系统会将相关的权限、属性、程序码与数据等均加载内存,并给予这个单元一个程序识别码 (PID),最终该命令可以进行的任务则与这个 PID 的权限有关。根据这个说明,我们就可以简单的了解,为什么 Linux 这么多用户,但是却每个人都可以拥有自己的环境了吧!^_^!底下我们来谈谈 Linux 多人多工环境的特色:
Linux 最棒的地方就在於他的多人多工环境了!那么什么是『多人多工』?在 Linux 系统上面具有多种不同的帐号,每种帐号都有都有其特殊的权限,只有一个人具有至高无上的权力,那就是root (系统管理员)。除了 root 之外,其他人都必须要受一些限制的!而每个人进入Linux 的环境配置都可以随著每个人的喜好来配置 (还记得我们在第十一章 BASH 提过的 ~/.bashrc 吧?对了!就是那个光!)!现在知道为什么了吧?因为每个人登陆后取得的 shell 的 PID 不同嘛!
我们在第零章谈到 CPU 的速度,目前的 CPU 速度可高达几个 GHz。这代表 CPU 每秒钟可以运行 109 这么多次命令。我们的 Linux 可以让 CPU 在各个工作间进行切换,也就是说,其实每个工作都仅占去 CPU 的几个命令次数,所以 CPU 每秒就能够在各个程序之间进行切换啦!谁叫 CPU 可以在一秒钟进行这么多次的命令运行。
CPU 切换程序的工作,与这些工作进入到 CPU 运行的排程 (CPU 排程,非 crontab 排程) 会影响到系统的整体效能!目前 Linux 使用的多工切换行为是非常棒的一个机制,几乎可以将 PC 的性能整个压榨出来!由於效能非常好,因此当多人同时登陆系统时,其实会感受到整部主机好像就为了你存在一般!这就是多人多工的环境啦!(注2)
在 Linux 当中,默认提供了六个文字界面登陆窗口,以及一个图形界面,你可以使用[Alt]+[F1].....[F7] 来切换不同的终端机界面,而且每个终端机界面的登陆者还可以不同人!很炫吧!这个东西可就很有用啦!尤其是在某个程序死掉的时候!
其实,这也是多工环境下所产生的一个情况啦!我们的 Linux 默认会启动六个终端机登陆环境的程序,所以我们就会有六个终端机介面。您也可以减少啊!就是减少启动的终端机程序就好了。详细的数据可以先查阅 /etc/inittab 这个文件,未来我们在启动管理流程 (第二十章) 会再仔细的介绍的!
以前的鸟哥笨笨的,总是以为使用 Windows 98 就可以啦!后来,因为工作的关系,需要使用 Unix 系统,想说我只要在工作机前面就好,才不要跑来跑去的到 Unix 工作站前面去呢!所以就使用 Windows 连到我的 Unix 工作站工作!好死不死,我一个程序跑下来要 2~3 天,唉~偏偏常常到了第 2.5 天的时候, Windows 98 就给他挂点去!当初真的是给他怕死了~
后来因为换了新计算机,用了随机版的 Windows 2000 ,呵呵,这东西真不错 (指对单人而言) ,在死机的时候,他可以仅将错误的程序踢掉,而不干扰其他的程序进行,呵呵!从此以后,就不用担心会死机连连罗!不过,2000 毕竟还不够好,因为有的时候还是会死当!
那么 Linux 会有这样的问题吗?老实说, Linux 几乎可以说绝对不会死机的!因为他可以在任何时候,将某个被困住的程序杀掉,然后再重新运行该程序而不用重新启动!够炫吧!那么如果我在Linux 下以文字界面登陆,在萤幕当中显示错误信息后就挂了~动都不能动,该如何是好!?这个时候那默认的七个窗口就帮上忙啦!你可以随意的再按[Alt]+[F1].....[F7] 来切换到其他的终端机界面,然后以ps -aux 找出刚刚的错误程序,然后给他kill 一下,哈哈,回到刚刚的终端机界面!恩~棒!又回复正常罗!
为什么可以这样做呢?我们刚刚不是提过吗?每个程序之间可能是独立的,也可能有相依性,只要到独立的程序当中,删除有问题的那个程序,当然他就可以被系统移除掉啦!^_^
我们在上一个小节有提到所谓的『父程序、子程序』的关系,那我们登陆 bash 之后,就是取得一个名为 bash 的 PID 了,而在这个环境底下所运行的其他命令,就几乎都是所谓的子程序了。那么,在这个单一的 bash 介面下,我可不可以进行多个工作啊?当然可以啦!可以『同时』进行喔!举例来说,我可以这样做:
[root@www ~]# cp file1 file2 &
|
在这一串命令中,重点在那个 & 的功能,他表示将 file1 这个文件复制为 file2 ,且放置於背景中运行,也就是说运行这一个命令之后,在这一个终端介面仍然可以做其他的工作!而当这一个命令 (cp file1 file2)运行完毕之后,系统将会在你的终端介面显示完成的消息!很便利喔!
多人多工确实有很多的好处,但其实也有管理上的困扰,因为使用者越来越多,将导致你管理上的困扰哩!另外,由於使用者日盛,当使用者达到一定的人数后,通常你的机器便需要升级了,因为 CPU 的运算与 RAM 的大小可能就会不敷使用!
举个例子来说,鸟哥之前的网站管理的有点不太好,因为使用了一个很复杂的人数统计程序,这个程序会一直去取用 MySQL 数据库的数据,偏偏因为流量大,造成 MySQL 很忙碌。在这样的情况下,当鸟哥要登陆去写网页数据,或者要去使用讨论区的资源时,哇!慢的很!简直就是『龟速』啊!后来终於将这个程序停止不用了,以自己写的一个小程序来取代,呵呵!这样才让 CPU 的负载 (loading) 整个降下来~用起来顺畅多了! ^_^
这个工作管理 (job control) 是用在 bash 环境下的,也就是说:『当我们登陆系统取得 bash shell之后,在单一终端机介面下同时进行多个工作的行为管理 』。举例来说,我们在登陆 bash 后,想要一边复制文件、一边进行数据搜寻、一边进行编译,还可以一边进行 vi 程序撰写!当然我们可以重复登陆那六个文字介面的终端机环境中,不过,能不能在一个 bash 内达成?当然可以啊!就是使用 job control 啦! ^_^
从上面的说明当中,你应该要了解的是:『进行工作管理的行为中,其实每个工作都是目前 bash 的子程序,亦即彼此之间是有相关性的。我们无法以 job control 的方式由 tty1 的环境去管理 tty2 的 bash !』这个概念请你得先创建起来,后续的范例介绍之后,你就会清楚的了解罗!
或许你会觉得很奇怪啊,既然我可以在六个终端介面登陆,那何必使用 job control 呢?真是脱裤子放屁,多此一举啊!不要忘记了呢,我们可以在 /etc/security/limits.conf (第十四章)里面配置使用者同时可以登陆的连线数,在这样的情况下,某些使用者可能仅能以一个连线来工作呢!所以罗,你就得要了解一下这种工作管理的模式了!此外,这个章节内容也会牵涉到很多的数据流重导向,所以,如果忘记的话,务必回到第十一章 BASH Shell 看一看喔!
由於假设我们只有一个终端介面,因此在可以出现提示字节让你操作的环境就称为前景 (foreground),至於其他工作就可以让你放入背景 (background) 去暂停或运行。要注意的是,放入背景的工作想要运行时,他必须不能够与使用者互动。举例来说, vim 绝对不可能在背景里面运行 (running) 的!因为你没有输入数据他就不会跑啊!而且放入背景的工作是不可以使用 [ctrl]+c 来终止的』!
总之,要进行 bash 的 job control 必须要注意到的限制是:
接下来让我们实际来管理这些工作吧!
如前所述,bash 只能够管理自己的工作而不能管理其他 bash 的工作,所以即使你是 root 也不能够将别人的 bash底下的 job 给他拿过来运行。此外,又分前景与背景,然后在背景里面的工作状态又可以分为『暂停 (stop)』与『运行中(running)』。那实际进行 job 控制的命令有哪些?底下就来谈谈。
如同前面提到的,我们在只有一个 bash 的环境下,如果想要同时进行多个工作,那么可以将某些工作直接丢到背景环境当中,让我们可以继续操作前景的工作!那么如何将工作丢到背景中?最简单的方法就是利用『 & 』这个玩意儿了!举个简单的例子,我们要将 /etc/ 整个备份成为 /tmp/etc.tar.gz 且不想要等待,那么可以这样做:
[root@www ~]# tar -zpcf /tmp/etc.tar.gz /etc & [1] 8400 <== [job number] PID [root@www ~]# tar: Removing leading `/' from member names # 在中括号内的号码为工作号码 (job number),该号码与 bash 的控制有关。 # 后续的 8400 则是这个工作在系统中的 PID。至於后续出现的数据是 tar 运行的数据流, # 由於我们没有加上数据流重导向,所以会影响画面!不过不会影响前景的操作喔! |
仔细的瞧一瞧,我在输入一个命令后,在该命令的最后面加上一个『 & 』代表将该命令丢到背景中,此时 bash 会给予这个命令一个『工作号码(job number)』,就是那个 [1] 啦!至於后面那个 8400 则是该命令所触发的『 PID 』了!而且,有趣的是,我们可以继续操作 bash 呢!很不赖吧!不过,那么丢到背景中的工作什么时候完成?完成的时候会显示什么?如果你输入几个命令后,突然出现这个数据:
[1]+ Done tar -zpcf /tmp/etc.tar.gz /etc |
就代表 [1] 这个工作已经完成 (Done) ,该工作的命令则是接在后面那一串命令列。这样了解了吧!另外,这个 & 代表:『将工作丢到背景中去运行』喔!注意到那个『运行』的字眼!此外,这样的情况最大的好处是:不怕被 [ctrl]+c 中断的啦!此外,将工作丢到背景当中要特别注意数据的流向喔!包括上面的信息就有出现错误信息,导致我的前景被影响。虽然只要按下 [enter] 就会出现提示字节。但如果我将刚刚那个命令改成:
[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc &
|
情况会怎样?在背景当中运行的命令,如果有 stdout 及 stderr 时,他的数据依旧是输出到萤幕上面的,所以,我们会无法看到提示字节,当然也就无法完好的掌握前景工作。同时由於是背景工作的 tar ,此时你怎么按下 [ctrl]+c 也无法停止萤幕被搞的花花绿绿的!所以罗,最佳的状况就是利用数据流重导向,将输出数据传送至某个文件中。举例来说,我可以这样做:
[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc > /tmp/log.txt 2>&1 &
[1] 8429
[root@www ~]#
|
呵呵!如此一来,输出的资讯都给他传送到 /tmp/log.txt 当中,当然就不会影响到我们前景的作业了。这样说,您应该可以更清楚数据流重导向的重要性了吧!^_^
Tips: 工作号码 (job number) 只与你这个 bash 环境有关,但是他既然是个命令触发的咚咚,所以当然一定是一个程序,因此你会观察到有 job number 也搭配一个 PID ! |
想个情况:如果我正在使用 vi ,却发现我有个文件不知道放在哪里,需要到 bash环境下进行搜寻,此时是否要结束 vi 呢?呵呵!当然不需要啊!只要暂时将 vi 给他丢到背景当中等待即可。例如以下的案例:
[root@www ~]# vi ~/.bashrc # 在 vi 的一般模式下,按下 [ctrl]-z 这两个按键 [1]+ Stopped vim ~/.bashrc [root@www ~]# <==顺利取得了前景的操控权! [root@www ~]# find / -print ....(输出省略).... # 此时萤幕会非常的忙碌!因为萤幕上会显示所有的档名。请按下 [ctrl]-z 暂停 [2]+ Stopped find / -print |
在 vi 的一般模式下,按下 [ctrl] 及 z 这两个按键,萤幕上会出现 [1] ,表示这是第一个工作,而那个 + 代表最近一个被丢进背景的工作,且目前在背景下默认会被取用的那个工作 (与 fg 这个命令有关 )!而那个 Stopped 则代表目前这个工作的状态。在默认的情况下,使用 [ctrl]-z 丢到背景当中的工作都是『暂停』的状态喔!
[root@www ~]# jobs [-lrs] 选项与参数: -l :除了列出 job number 与命令串之外,同时列出 PID 的号码; -r :仅列出正在背景 run 的工作; -s :仅列出正在背景当中暂停 (stop) 的工作。 范例一:观察目前的 bash 当中,所有的工作,与对应的 PID [root@www ~]# jobs -l [1]- 10314 Stopped vim ~/.bashrc [2]+ 10833 Stopped find / -print |
如果想要知道目前有多少的工作在背景当中,就用 jobs 这个命令吧!一般来说,直接下达 jobs 即可!不过,如果你还想要知道该 job number 的 PID 号码,可以加上 -l 这个参数啦!在输出的资讯当中,例如上表,仔细看到那个 + - 号喔!那个 + 代表默认的取用工作。所以说:『目前我有两个工作在背景当中,两个工作都是暂停的,而如果我仅输入 fg 时,那么那个 [2] 会被拿到前景当中来处理』!
其实 + 代表最近被放到背景的工作号码, - 代表最近最后第二个被放置到背景中的工作号码。而超过最后第三个以后的工作,就不会有 +/- 符号存在了!
刚刚提到的都是将工作丢到背景当中去运行的,那么有没有可以将背景工作拿到前景来处理的?有啊!就是那个 fg (foreground) 啦!举例来说,我们想要将上头范例当中的工作拿出来处理时:
[root@www ~]# fg %jobnumber 选项与参数: %jobnumber :jobnumber 为工作号码(数字)。注意,那个 % 是可有可无的! 范例一:先以 jobs 观察工作,再将工作取出: [root@www ~]# jobs [1]- 10314 Stopped vim ~/.bashrc [2]+ 10833 Stopped find / -print [root@www ~]# fg <==默认取出那个 + 的工作,亦即 [2]。立即按下[ctrl]-z [root@www ~]# fg %1 <==直接规定取出的那个工作号码!再按下[ctrl]-z [root@www ~]# jobs [1]+ Stopped vim ~/.bashrc [2]- Stopped find / -print |
经过 fg 命令就能够将背景工作拿到前景来处理罗!不过比较有趣的是最后一个显示的结果,我们会发现 + 出现在第一个工作后!怎么会这样啊?这是因为你刚刚利用 fg %1 将第一号工作捉到前景后又放回背景,此时最后一个被放入背景的将变成 vi 那个命令动作,所以当然 [1] 后面就会出现 + 了!了解乎!另外,如果输入『 fg -』则代表将 - 号的那个工作号码拿出来,上面就是 [2]- 那个工作号码啦!
我们刚刚提到,那个 [ctrl]-z 可以将目前的工作丢到背景底下去『暂停』,那么如何让一个工作在背景底下『 Run 』呢?我们可以在底下这个案例当中来测试!注意喔!底下的测试要进行的快一点!^_^
范例一:一运行 find / -perm +7000 > /tmp/text.txt 后,立刻丢到背景去暂停! [root@www ~]# find / -perm +7000 > /tmp/text.txt # 此时,请立刻按下 [ctrl]-z 暂停! [3]+ Stopped find / -perm +7000 > /tmp/text.txt 范例二:让该工作在背景下进行,并且观察他!! [root@www ~]# jobs ; bg %3 ; jobs [1]- Stopped vim ~/.bashrc [2] Stopped find / -print [3]+ Stopped find / -perm +7000 > /tmp/text.txt [3]+ find / -perm +7000 > /tmp/text.txt & <==用 bg%3 的情况! [1]+ Stopped vim ~/.bashrc [2] Stopped find / -print [3]- Running find / -perm +7000 > /tmp/text.txt & |
看到哪里有差异吗?呼呼!没错!就是那个状态列~以经由 Stopping 变成了 Running 罗!看到差异点,嘿嘿!命令列最后方多了一个 & 的符号罗!代表该工作被启动在背景当中了啦! ^_^
刚刚我们可以让一个已经在背景当中的工作继续工作,也可以让该工作以 fg 拿到前景来,那么,如果想要将该工作直接移除呢?或者是将该工作重新启动呢?这个时候就得需要给予该工作一个讯号 (signal) ,让他知道该怎么作才好啊!此时, kill 这个命令就派上用场啦!
[root@www ~]# kill -signal %jobnumber [root@www ~]# kill -l 选项与参数: -l :这个是 L 的小写,列出目前 kill 能够使用的讯号 (signal) 有哪些? signal :代表给予后面接的那个工作什么样的指示罗!用 man 7 signal 可知: -1 :重新读取一次参数的配置档 (类似 reload); -2 :代表与由键盘输入 [ctrl]-c 同样的动作; -9 :立刻强制删除一个工作; -15:以正常的程序方式终止一项工作。与 -9 是不一样的。 范例一:找出目前的 bash 环境下的背景工作,并将该工作『强制删除』。 [root@www ~]# jobs [1]+ Stopped vim ~/.bashrc [2] Stopped find / -print [root@www ~]# kill -9 %2; jobs [1]+ Stopped vim ~/.bashrc [2] Killed find / -print # 再过几秒你再下达 jobs 一次,就会发现 2 号工作不见了!因为被移除了! 范例:找出目前的 bash 环境下的背景工作,并将该工作『正常终止』掉。 [root@www ~]# jobs [1]+ Stopped vim ~/.bashrc [root@www ~]# kill -SIGTERM %1 # -SIGTERM 与 -15 是一样的!您可以使用 kill -l 来查阅! |
特别留意一下, -9 这个 signal 通常是用在『强制删除一个不正常的工作』时所使用的,-15 则是以正常步骤结束一项工作(15也是默认值),两者之间并不相同呦!举上面的例子来说,我用 vi 的时候,不是会产生一个 .filename.swp 的文件吗?那么,当使用 -15 这个 signal 时, vi 会尝试以正常的步骤来结束掉该 vi 的工作,所以 .filename.swp 会主动的被移除。但若是使用 -9 这个 signal 时,由於该 vi 工作会被强制移除掉,因此, .filename.swp 就会继续存在文件系统当中。这样您应该可以稍微分辨一下了吧?
其实, kill 的妙用是很无穷的啦!他搭配 signal 所详列的资讯 (用 man 7 signal 去查阅相关数据)可以让您有效的管理工作与程序 (Process),此外,那个 killall 也是同样的用法!至於常用的 signal 您至少需要了解 1, 9, 15 这三个 signal 的意义才好。此外, signal 除了以数值来表示之外,也可以使用讯号名称喔!举例来说,上面的范例二就是一个例子啦!至於 signal number 与名称的对应,呵呵,使用 kill -l 就知道啦(L的小写)!
另外, kill 后面接的数字默认会是 PID ,如果想要管理 bash 的工作控制,就得要加上 %数字 了,这点也得特别留意才行喔!
要注意的是,我们在工作管理当中提到的『背景』指的是在终端机模式下可以避免 [crtl]-c 中断的一个情境,并不是放到系统的背景去喔!所以,工作管理的背景依旧与终端机有关啦!在这样的情况下,如果你是以远程连线方式连接到你的 Linux 主机,并且将工作以 & 的方式放到背景去,请问,在工作尚未结束的情况下你离线了,该工作还会继续进行吗?答案是『否』!不会继续进行,而是会被中断掉。
那怎么办?如果我的工作需要进行一大段时间,我又不能放置在背景底下,那该如何处理呢?首先,你可以参考前一章的 at 来处理即可!因为 at 是将工作放置到系统背景,而与终端机无关。如果不想要使用 at 的话,那你也可以尝试使用 nohup 这个命令来处理喔!这个 nohup 可以让你在离线或注销系统后,还能够让工作继续进行。他的语法有点像这样:
[root@www ~]# nohup [命令与参数] <==在终端机前景中工作 [root@www ~]# nohup [命令与参数] & <==在终端机背景中工作 |
有够好简单的命令吧!上述命令需要注意的是, nohup 并不支持 bash 内建的命令,因此你的命令必须要是外部命令才行。我们来尝试玩一下底下的任务吧!
# 1. 先编辑一支会『睡著 500 秒』的程序: [root@www ~]# vim sleep500.sh #!/bin/bash /bin/sleep 500s /bin/echo "I have slept 500 seconds." # 2. 丢到背景中去运行,并且立刻注销系统: [root@www ~]# chmod a+x sleep500.sh [root@www ~]# nohup ./sleep500.sh & [1] 5074 [root@www ~]# nohup: appending output to ‘nohup.out’ <==会告知这个信息! [root@www ~]# exit |
如果你再次登陆的话,再使用 pstree 去查阅你的程序,会发现 sleep500.sh 还在运行中喔!并不会被中断掉!这样了解意思了吗?由於我们的程序最后会输出一个信息,但是 nohup 与终端机其实无关了,因此这个信息的输出就会被导向『 ~/nohup.out 』,所以你才会看到上述命令中,当你输入 nohup 后,会出现那个提示信息罗。
如果你想要让在背景的工作在你注销后还能够继续的运行,那么使用 nohup 搭配 & 是不错的运行情境喔!可以参考看看!
本章一开始就提到所谓的『程序』的概念,包括程序的触发、子程序与父程序的相关性等等,此外,还有那个『程序的相依性』以及所谓的『僵尸程序』等等需要说明的呢!为什么程序管理这么重要呢?这是因为:
所以罗,一个称职的系统管理员,必须要熟悉程序的管理流程才行,否则当系统发生问题时,还真是很难解决问题呢!底下我们会先介绍如何观察程序与程序的状态,然后再加以程序控制罗!
既然程序这么重要,那么我们如何查阅系统上面正在运行当中的程序呢?很简单啊!利用静态的 ps 或者是动态的 top,还能以 pstree 来查阅程序树之间的关系喔!
[root@www ~]# ps aux <==观察系统所有的程序数据 [root@www ~]# ps -lA <==也是能够观察所有系统的数据 [root@www ~]# ps axjf <==连同部分程序树状态 选项与参数: -A :所有的 process 均显示出来,与 -e 具有同样的效用; -a :不与 terminal 有关的所有 process ; -u :有效使用者 (effective user) 相关的 process ; x :通常与 a 这个参数一起使用,可列出较完整资讯。 输出格式规划: l :较长、较详细的将该 PID 的的资讯列出; j :工作的格式 (jobs format) -f :做一个更为完整的输出。 |
鸟哥个人认为 ps 这个命令的 man page 不是很好查阅,因为很多不同的 Unix 都使用这个 ps 来查阅程序状态,为了要符合不同版本的需求,所以这个 man page 写的非常的庞大!因此,通常鸟哥都会建议你,直接背两个比较不同的选项,一个是只能查阅自己 bash 程序的『 ps -l 』一个则是可以查阅所有系统运行的程序『 ps aux 』!注意,你没看错,是『 ps aux 』没有那个减号 (-) !先来看看关於自己 bash 程序状态的观察:
范例一:将目前属於您自己这次登陆的 PID 与相关资讯列示出来(只与自己的 bash 有关) [root@www ~]# ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 13639 13637 0 75 0 - 1287 wait pts/1 00:00:00 bash 4 R 0 13700 13639 0 77 0 - 1101 - pts/1 00:00:00 ps |
系统整体的程序运行是非常多的,但如果使用 ps -l 则仅列出与你的操作环境 (bash) 有关的程序而已,亦即最上一级的父程序会是你自己的 bash 而没有延伸到 init 这支程序去!那么 ps -l 秀出来的数据有哪些呢?我们就来观察看看:
所以你看到的 ps -l 输出信息中,他说明的是:『bash 的程序属於 UID 为 0 的使用者,状态为睡眠 (sleep),之所以为睡眠因为他触发了 ps (状态为 run) 之故。此程序的 PID 为 13639,优先运行顺序为 75 ,下达 bash 所取得的终端介面为 pts/1 ,运行状态为等待 (wait) 。』这样已经够清楚了吧?您自己尝试解析一下那么 ps 那一行代表的意义为何呢? ^_^
接下来让我们使用 ps 来观察一下系统内所有的程序状态吧!
范例二:列出目前所有的正在内存当中的程序: [root@www ~]# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 2064 616 ? Ss Mar11 0:01 init [5] root 2 0.0 0.0 0 0 ? S< Mar11 0:00 [migration/0] root 3 0.0 0.0 0 0 ? SN Mar11 0:00 [ksoftirqd/0] .....(中间省略)..... root 13639 0.0 0.2 5148 1508 pts/1 Ss 11:44 0:00 -bash root 14232 0.0 0.1 4452 876 pts/1 R+ 15:52 0:00 ps aux root 18593 0.0 0.0 2240 476 ? Ss Mar14 0:00 /usr/sbin/atd |
你会发现 ps -l 与 ps aux 显示的项目并不相同!在 ps aux 显示的项目中,各栏位的意义为:
一般来说,ps aux 会依照 PID 的顺序来排序显示,我们还是以 13639 那个 PID 那行来说明!该行的意义为『root 运行的 bash PID 为 13639,占用了 0.2% 的内存容量百分比,状态为休眠 (S),该程序启动的时间为 11:44 ,且取得的终端机环境为 pts/1 。』与 ps aux 看到的其实是同一个程序啦!这样可以理解吗?让我们继续使用 ps 来观察一下其他的资讯吧!
范例三:以范例一的显示内容,显示出所有的程序: [root@www ~]# ps -lA F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 1 0 0 76 0 - 435 - ? 00:00:01 init 1 S 0 2 1 0 94 19 - 0 ksofti ? 00:00:00 ksoftirqd/0 1 S 0 3 1 0 70 -5 - 0 worker ? 00:00:00 events/0 ....(以下省略).... # 你会发现每个栏位与 ps -l 的输出情况相同,但显示的程序则包括系统所有的程序。 范例四:列出类似程序树的程序显示: [root@www ~]# ps axjf PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 0 1 1 1 ? -1 Ss 0 0:01 init [5] .....(中间省略)..... 1 4586 4586 4586 ? -1 Ss 0 0:00 /usr/sbin/sshd 4586 13637 13637 13637 ? -1 Ss 0 0:00 \_ sshd: root@pts/1 13637 13639 13639 13639 pts/1 14266 Ss 0 0:00 \_ -bash 13639 14266 14266 13639 pts/1 14266 R+ 0 0:00 \_ ps axjf .....(后面省略)..... |
看出来了吧?其实鸟哥在进行一些测试时,都是以网络连线进主机来测试的,所以罗,你会发现其实程序之间是有相关性的啦!不过,其实还可以使用 pstree 来达成这个程序树喔!以上面的例子来看,鸟哥是透过 sshd 提供的网络服务取得一个程序,该程序提供 bash 给我使用,而我透过 bash 再去运行 ps axjf !这样可以看的懂了吗?其他各栏位的意义请 man ps (虽然真的很难 man 的出来!) 罗!
范例五:找出与 cron 与 syslog 这两个服务有关的 PID 号码? [root@www ~]# ps aux | egrep '(cron|syslog)' root 4286 0.0 0.0 1720 572 ? Ss Mar11 0:00 syslogd -m 0 root 4661 0.0 0.1 5500 1192 ? Ss Mar11 0:00 crond root 14286 0.0 0.0 4116 592 pts/1 R+ 16:15 0:00 egrep (cron|syslog) # 所以号码是 4286 及 4661 这两个罗!就是这样找的啦! |
除此之外,我们必须要知道的是『僵尸 (zombie) 』程序是什么?通常,造成僵尸程序的成因是因为该程序应该已经运行完毕,或者是因故应该要终止了,但是该程序的父程序却无法完整的将该程序结束掉,而造成那个程序一直存在内存当中。如果你发现在某个程序的 CMD 后面还接上
apache 8683 0.0 0.9 83384 9992 ? Z 14:33 0:00 /usr/sbin/httpd |
当系统不稳定的时候就容易造成所谓的僵尸程序,可能是因为程序写的不好啦,或者是使用者的操作习惯不良等等所造成。如果你发现系统中很多僵尸程序时,记得啊!要找出该程序的父程序,然后好好的做个追踪,好好的进行主机的环境最佳化啊!看看有什么地方需要改善的,不要只是直接将他 kill 掉而已呢!不然的话,万一他一直产生,那可就麻烦了! @_@
事实上,通常僵尸程序都已经无法控管,而直接是交给 init 这支程序来负责了,偏偏 init 是系统第一支运行的程序,他是所有程序的父程序!我们无法杀掉该程序的 (杀掉他,系统就死掉了!),所以罗,如果产生僵尸程序,而系统过一阵子还没有办法透过核心非经常性的特殊处理来将该程序删除时,那你只好透过 reboot 的方式来将该程序抹去了!
相对於 ps 是撷取一个时间点的程序状态, top 则可以持续侦测程序运行的状态!使用方式如下:
[root@www ~]# top [-d 数字] | top [-bnp] 选项与参数: -d :后面可以接秒数,就是整个程序画面升级的秒数。默认是 5 秒; -b :以批量的方式运行 top ,还有更多的参数可以使用喔! 通常会搭配数据流重导向来将批量的结果输出成为文件。 -n :与 -b 搭配,意义是,需要进行几次 top 的输出结果。 -p :指定某些个 PID 来进行观察监测而已。 在 top 运行过程当中可以使用的按键命令: ? :显示在 top 当中可以输入的按键命令; P :以 CPU 的使用资源排序显示; M :以 Memory 的使用资源排序显示; N :以 PID 来排序喔! T :由该 Process 使用的 CPU 时间累积 (TIME+) 排序。 k :给予某个 PID 一个讯号 (signal) r :给予某个 PID 重新制订一个 nice 值。 q :离开 top 软件的按键。 |
其实 top 的功能非常多!可以用的按键也非常的多!可以参考 man top 的内部说明文件!鸟哥这里仅是列出一些鸟哥自己常用的选项而已。接下来让我们实际观察一下如何使用 top 与 top 的画面吧!
范例一:每两秒钟升级一次 top ,观察整体资讯: [root@www ~]# top -d 2 top - 17:03:09 up 7 days, 16:16, 1 user, load average: 0.00, 0.00, 0.00 Tasks: 80 total, 1 running, 79 sleeping, 0 stopped, 0 zombie Cpu(s): 0.5%us, 0.5%sy, 0.0%ni, 99.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 742664k total, 681672k used, 60992k free, 125336k buffers Swap: 1020088k total, 28k used, 1020060k free, 311156k cached <==如果加入 k 或 r 时,就会有相关的字样出现在这里喔! PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 14398 root 15 0 2188 1012 816 R 0.5 0.1 0:00.05 top 1 root 15 0 2064 616 528 S 0.0 0.1 0:01.38 init 2 root RT -5 0 0 0 S 0.0 0.0 0:00.00 migration/0 3 root 34 19 0 0 0 S 0.0 0.0 0:00.00 ksoftirqd/0 |
top 也是个挺不错的程序观察工具!但不同於 ps 是静态的结果输出, top 这个程序可以持续的监测整个系统的程序工作状态。在默认的情况下,每次升级程序资源的时间为 5 秒,不过,可以使用 -d 来进行修改。top 主要分为两个画面,上面的画面为整个系统的资源使用状态,基本上总共有六行,显示的内容依序是:
至於 top 下半部分的画面,则是每个 process 使用的资源情况。比较需要注意的是:
top 默认使用 CPU 使用率 (%CPU) 作为排序的重点,如果你想要使用内存使用率排序,则可以按下『M』,若要回复则按下『P』即可。如果想要离开 top 则按下『 q 』吧!如果你想要将 top 的结果输出成为文件时,可以这样做:
范例二:将 top 的资讯进行 2 次,然后将结果输出到 /tmp/top.txt [root@www ~]# top -b -n 2 > /tmp/top.txt # 这样一来,嘿嘿!就可以将 top 的资讯存到 /tmp/top.txt 文件中了。 |
这玩意儿很有趣!可以帮助你将某个时段 top 观察到的结果存成文件,可以用在你想要在系统背景底下运行。由於是背景底下运行,与终端机的萤幕大小无关,因此可以得到全部的程序画面!那如果你想要观察的程序 CPU与内存使用率都很低,结果老是无法在第一行显示时,该怎办?我们可以仅观察单一程序喔!如下所示:
范例三:我们自己的 bash PID 可由 $$ 变量取得,请使用 top 持续观察该 PID [root@www ~]# echo $$ 13639 <==就是这个数字!他是我们 bash 的 PID [root@www ~]# top -d 2 -p 13639 top - 17:31:56 up 7 days, 16:45, 1 user, load average: 0.00, 0.00, 0.00 Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 742664k total, 682540k used, 60124k free, 126548k buffers Swap: 1020088k total, 28k used, 1020060k free, 311276k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 13639 root 15 0 5148 1508 1220 S 0.0 0.2 0:00.18 bash |
看到没!就只会有一支程序给你看!很容易观察吧!好,那么如果我想要在 top 底下进行一些动作呢?比方说,修改 NI 这个数值呢?可以这样做:
范例四:承上题,上面的 NI 值是 0 ,想要改成 10 的话? # 在范例三的 top 画面当中直接按下 r 之后,会出现如下的图样! top - 17:34:24 up 7 days, 16:47, 1 user, load average: 0.00, 0.00, 0.00 Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie Cpu(s): 0.0%us, 0.0%sy, 0.0%ni, 99.5%id, 0.0%wa, 0.0%hi, 0.5%si, 0.0%st Mem: 742664k total, 682540k used, 60124k free, 126636k buffers Swap: 1020088k total, 28k used, 1020060k free, 311276k cached PID to renice: 13639 <==按下 r 然后输入这个 PID 号码 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 13639 root 15 0 5148 1508 1220 S 0.0 0.2 0:00.18 bash |
在你完成上面的动作后,在状态列会出现如下的资讯:
Renice PID 13639 to value: 10 <==这是 nice 值 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND |
接下来你就会看到如下的显示画面!
top - 17:38:58 up 7 days, 16:52, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 742664k total, 682540k used, 60124k free, 126648k buffers
Swap: 1020088k total, 28k used, 1020060k free, 311276k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
13639 root 26 10 5148 1508 1220 S 0.0 0.2 0:00.18 bash
|
看到不同处了吧?底线的地方就是修改了之后所产生的效果!一般来说,如果鸟哥想要找出最损耗 CPU 资源的那个程序时,大多使用的就是 top 这支程序啦!然后强制以 CPU 使用资源来排序 (在 top 当中按下 P 即可),就可以很快的知道啦! ^_^。多多爱用这个好用的东西喔!
[root@www ~]# pstree [-A|U] [-up] 选项与参数: -A :各程序树之间的连接以 ASCII 字节来连接; -U :各程序树之间的连接以万国码的字节来连接。在某些终端介面下可能会有错误; -p :并同时列出每个 process 的 PID; -u :并同时列出每个 process 的所属帐号名称。 范例一:列出目前系统上面所有的程序树的相关性: [root@www ~]# pstree -A init-+-acpid |-atd |-auditd-+-audispd---{audispd} <==这行与底下一行为 auditd 分出来的子程序 | `-{auditd} |-automount---4*[{automount}] <==默认情况下,相似的程序会以数字显示 ....(中间省略).... |-sshd---sshd---bash---pstree <==就是我们命令运行的那个相依性! ....(底下省略).... # 注意一下,为了节省版面,所以鸟哥已经删去很多程序了! 范例二:承上题,同时秀出 PID 与 users [root@www ~]# pstree -Aup init(1)-+-acpid(4555) |-atd(18593) |-auditd(4256)-+-audispd(4258)---{audispd}(4261) | `-{auditd}(4257) |-automount(4536)-+-{automount}(4537) <==程序相似但 PID 不同! | |-{automount}(4538) | |-{automount}(4541) | `-{automount}(4544) ....(中间省略).... |-sshd(4586)---sshd(16903)---bash(16905)---pstree(16967) ....(中间省略).... |-xfs(4692,xfs) <==因为此程序拥有者并非运行 pstree 者!所以列出帐号 ....(底下省略).... # 在括号 () 内的即是 PID 以及该程序的 owner 喔!不过,由於我是使用 # root 的身份运行此一命令,所以属於 root 的程序就不会显示出来啦! |
如果要找程序之间的相关性,这个 pstree 真是好用到不行!直接输入 pstree 可以查到程序相关性,如上表所示,还会使用线段将相关性程序连结起来哩!一般连结符号可以使用 ASCII 码即可,但有时因为语系问题会主动的以 Unicode 的符号来连结,但因为可能终端机无法支持该编码,或许会造成乱码问题。因此可以加上 -A 选项来克服此类线段乱码问题。
由 pstree 的输出我们也可以很清楚的知道,所有的程序都是依附在 init 这支程序底下的!仔细看一下,这支程序的 PID 是一号喔!因为他是由 Linux 核心所主动呼叫的第一支程序!所以 PID 就是一号了。这也是我们刚刚提到僵尸程序时有提到,为啥发生僵尸程序需要重新启动?因为 init 要重新启动,而重新启动 init 就是 reboot 罗!
如果还想要知道 PID 与所属使用者,加上 -u 及 -p 两个参数即可。我们前面不是一直提到,如果子程序挂点或者是老是砍不掉子程序时,该如何找到父程序吗?呵呵!用这个 pstree 就对了! ^_^
程序之间是可以互相控制的!举例来说,你可以关闭、重新启动服务器软件,服务器软件本身是个程序,你既然可以让她关闭或启动,当然就是可以控制该程序啦!那么程序是如何互相管理的呢?其实是透过给予该程序一个讯号 (signal)去告知该程序你想要让她作什么!因此这个讯号就很重要啦!
我们也在本章之前的 bash 工作管理当中提到过,要给予某个已经存在背景中的工作某些动作时,是直接给予一个讯号给该工作号码即可。那么到底有多少 signal 呢?你可以使用 kill -l (小写的 L ) 或者是 man 7 signal 都可以查询到!主要的讯号代号与名称对应及内容是:
代号 | 名称 | 内容 |
1 | SIGHUP | 启动被终止的程序,可让该 PID 重新读取自己的配置档,类似重新启动 |
2 | SIGINT | 相当於用键盘输入 [ctrl]-c 来中断一个程序的进行 |
9 | SIGKILL | 代表强制中断一个程序的进行,如果该程序进行到一半,那么尚未完成的部分可能会有『半产品』产生,类似 vim会有 .filename.swp 保留下来。 |
15 | SIGTERM | 以正常的结束程序来终止该程序。由於是正常的终止,所以后续的动作会将他完成。不过,如果该程序已经发生问题,就是无法使用正常的方法终止时,输入这个 signal 也是没有用的。 |
17 | SIGSTOP | 相当於用键盘输入 [ctrl]-z 来暂停一个程序的进行 |
上面仅是常见的 signal 而已,更多的讯号资讯请自行 man 7 signal 吧!一般来说,你只要记得『1, 9, 15』这三个号码的意义即可。那么我们如何传送一个讯号给某个程序呢?就透过 kill 或 killall 吧!底下分别来看看:
kill 可以帮我们将这个 signal 传送给某个工作 (%jobnumber) 或者是某个 PID (直接输入数字)。要再次强调的是: kill 后面直接加数字与加上 %number 的情况是不同的!这个很重要喔!因为工作控制中有 1 号工作,但是 PID 1 号则是专指『 init 』这支程序!你怎么可以将 init 关闭呢?关闭 init ,你的系统就当掉了啊!所以记得那个 % 是专门用在工作控制的喔!我们就活用一下 kill 与刚刚上面提到的 ps 来做个简单的练习吧!
例题:
以 ps 找出 syslog 这个程序的 PID 后,再使用 kill 传送信息,使得 syslog 可以重新读取配置档。
答:
由於需要重新读取配置档,因此 signal 是 1 号。至於找出 syslog 的 PID 可以是这样做:
ps aux | grep 'syslog' | grep -v 'grep'| awk '{print $2}'接下来则是实际使用 kill -1 PID,因此,整串命令会是这样: kill -SIGHUP $(ps aux|grep 'syslog'|grep -v 'grep'|awk '{print $2}')如果要确认有没有重新启动 syslog ,可以参考登录档的内容,使用如下命令查阅: tail -5 /var/log/messages如果你有看到类似『Mar 19 15:08:20 www syslogd 1.4.1: restart』之类的字样,就是表示 syslogd 在 3/19 有重新启动 (restart) 过了! |
了解了这个用法以后,如果未来你想要将某个莫名其妙的登陆者的连线删除的话,就可以透过使用 pstree -p 找到相关程序,然后再以 kill -9 将该程序删除,该条连线就会被踢掉了!这样很简单吧!
由於 kill 后面必须要加上 PID (或者是 job number),所以,通常 kill 都会配合ps,pstree 等命令,因为我们必须要找到相对应的那个程序的 ID 嘛!但是,如此一来,很麻烦~有没有可以利用『下达命令的名称』来给予讯号的?举例来说,能不能直接将 syslog 这个程序给予一个 SIGHUP 的讯号呢?可以的!用 killall 吧!
[root@www ~]# killall [-iIe] [command name] 选项与参数: -i :interactive 的意思,互动式的,若需要删除时,会出现提示字节给使用者; -e :exact 的意思,表示『后面接的 command name 要一致』,但整个完整的命令 不能超过 15 个字节。 -I :命令名称(可能含参数)忽略大小写。 范例一:给予 syslogd 这个命令启动的 PID 一个 SIGHUP 的讯号 [root@www ~]# killall -1 syslogd # 如果用 ps aux 仔细看一下,syslogd 才是完整的命令名称。但若包含整个参数, # 则 syslogd -m 0 才是完整的呢! 范例二:强制终止所有以 httpd 启动的程序 [root@www ~]# killall -9 httpd 范例三:依次询问每个 bash 程序是否需要被终止运行! [root@www ~]# killall -i -9 bash Kill bash(16905) ? (y/N) n <==这个不杀! Kill bash(17351) ? (y/N) y <==这个杀掉! # 具有互动的功能!可以询问你是否要删除 bash 这个程序。要注意,若没有 -i 的参数, # 所有的 bash 都会被这个 root 给杀掉!包括 root 自己的 bash 喔! ^_^ |
总之,要删除某个程序,我们可以使用 PID 或者是启动该程序的命令名称,而如果要删除某个服务呢?呵呵!最简单的方法就是利用 killall ,因为他可以将系统当中所有以某个命令名称启动的程序全部删除。举例来说,上面的范例二当中,系统内所有以 httpd 启动的程序,就会通通的被删除啦! ^_^
我们知道 Linux 是多人多工的环境,由 top 的输出结果我们也发现,系统同时间有非常多的程序在运行中,只是绝大部分的程序都在休眠 (sleeping) 状态而已。想一想,如果所有的程序同时被唤醒,那么 CPU 应该要先处理那个程序呢?也就是说,那个程序被运行的优先序比较高?这就得要考虑到程序的优先运行序 (Priority) 与 CPU 排程罗!
Tips: CPU 排程与前一章的例行性工作排程并不一样。 CPU 排程指的是每支程序被 CPU 运行的演算守则,而例行性工作排程则是将某支程序安排在某个时间再交由系统运行。 CPU 排程与操作系统较具有相关性! |
我们知道 CPU 一秒钟可以运行多达数 G 的微命令次数,透过核心的 CPU 排程可以让各程序被 CPU 所切换运行,因此每个程序在一秒钟内或多或少都会被 CPU 运行部分的命令码。如果程序都是集中在一个伫列中等待 CPU 的运行,而不具有优先顺序之分,也就是像我们去游乐场玩热门游戏需要排队一样,每个人都是照顺序来!你玩过一遍后还想再玩 (没有运行完毕),请到后面继续排队等待。情况有点像底下这样:
上图中假设 pro1, pro2 是紧急的程序, pro3, pro4 是一般的程序,在这样的环境中,由於不具有优先顺序,唉啊!pro1, pro2 还是得要继续等待而没有优待呢!如果 pro3, pro4 的工作又臭又长!那么紧急的 pro1, pro2 就得要等待个老半天才能够完成!真麻烦啊!所以罗,我们想要将程序分优先顺序啦!如果优先序较高则运行次数可以较多次,而不需要与较慢优先的程序抢位置!我们可以将程序的优先顺序与 CPU 排程进行如下图的解释:
如上图所示,具高优先权的 pro1, pro2 可以被取用两次,而较不重要的 pro3, pro4 则运行次数较少。如此一来 pro1, pro2 就可以较快被完成啦!要注意,上图仅是示意图,并非较优先者一定会被运行两次啦!为了要达到上述的功能,我们 Linux 给予程序一个所谓的『优先运行序 (priority, PRI)』,这个PRI 值越低代表越优先的意思。不过这个 PRI 值是由核心动态调整的,使用者无法直接调整 PRI 值的。先来瞧瞧 PRI 曾在哪里出现?
[root@www ~]# ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 18625 18623 2 75 0 - 1514 wait pts/1 00:00:00 bash 4 R 0 18653 18625 0 77 0 - 1102 - pts/1 00:00:00 ps |
由於 PRI 是核心动态调整的,我们使用者也无权去干涉 PRI !那如果你想要调整程序的优先运行序时,就得要透过 Nice值了!Nice 值就是上表的 NI 啦!一般来说, PRI 与 NI 的相关性如下:
PRI(new) = PRI(old) + nice
不过你要特别留意到,如果原本的 PRI 是 50 ,并不是我们给予一个 nice = 5 ,就会让 PRI 变成 55 喔!因为 PRI 是系统『动态』决定的,所以,虽然 nice 值是可以影响 PRI ,不过,最终的 PRI 仍是要经过系统分析后才会决定的。另外, nice 值是有正负的喔,而既然 PRI 越小越早被运行,所以,当 nice 值为负值时,那么该程序就会降低 PRI 值,亦即会变的较优先被处理。此外,你必须要留意到:
这也就是说,要调整某个程序的优先运行序,就是『调整该程序的 nice 值』啦!那么如何给予某个程序 nice值呢?有两种方式,分别是:
[root@www ~]# nice [-n 数字] command 选项与参数: -n :后面接一个数值,数值的范围 -20 ~ 19。 范例一:用 root 给一个 nice 值为 -5 ,用於运行 vi ,并观察该程序! [root@www ~]# nice -n -5 vi & [1] 18676 [root@www ~]# ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 18625 18623 0 75 0 - 1514 wait pts/1 00:00:00 bash 4 T 0 18676 18625 0 72 -5 - 1242 finish pts/1 00:00:00 vi 4 R 0 18678 18625 0 77 0 - 1101 - pts/1 00:00:00 ps # 原本的 bash PRI 为 75 ,所以 vi 默认应为 75。不过由於给予 nice 为 -5 , # 因此 vi 的 PRI 降低了!但并非降低到 70 ,因为核心还会动态调整! [root@www ~]# kill -9 %1 <==测试完毕将 vi 关闭 |
就如同前面说的, nice 是用来调整程序的运行优先顺序!这里只是一个运行的范例罢了!通常什么时候要将 nice 值调大呢?举例来说,系统的背景工作中,某些比较不重要的程序之进行:例如备份工作!由於备份工作相当的耗系统资源,这个时候就可以将备份的命令之 nice 值调大一些,可以使系统的资源分配的更为公平!
[root@www ~]# renice [number] PID 选项与参数: PID :某个程序的 ID 啊! 范例一:找出自己的 bash PID ,并将该 PID 的 nice 调整到 10 [root@www ~]# ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 18625 18623 0 75 0 - 1514 wait pts/1 00:00:00 bash 4 R 0 18712 18625 0 77 0 - 1102 - pts/1 00:00:00 ps [root@www ~]# renice 10 18625 18625: old priority 0, new priority 10 [root@www ~]# ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 18625 18623 0 85 10 - 1514 wait pts/1 00:00:00 bash 4 R 0 18715 18625 0 87 10 - 1102 - pts/1 00:00:00 ps |
如果要调整的是已经存在的某个程序的话,那么就得要使用 renice 了。使用的方法很简单,renice 后面接上数值及 PID 即可。因为后面接的是 PID ,所以你务必要以 ps 或者其他程序观察的命令去找出 PID 才行啊!
由上面这个范例当中我们也看的出来,虽然修改的是 bash 那个程序,但是该程序所触发的 ps 命令当中的 nice 也会继承而为 10 喔!了解了吧!整个 nice 值是可以在父程序 --> 子程序之间传递的呢!另外,除了 renice 之外,其实那个top 同样的也是可以调整 nice 值的!
除了系统的程序之外,我们还必须就系统的一些资源进行检查啊!举例来说,我们使用 top 可以看到很多系统的资源对吧!那么,还有没有其他的工具可以查阅的?当然有啊!底下这些工具命令可以玩一玩!
[root@www ~]# free [-b|-k|-m|-g] [-t] 选项与参数: -b :直接输入 free 时,显示的单位是 Kbytes,我们可以使用 b(bytes), m(Mbytes) k(Kbytes), 及 g(Gbytes) 来显示单位喔! -t :在输出的最终结果,显示实体内存与 swap 的总量。 范例一:显示目前系统的内存容量 [root@www ~]# free -m total used free shared buffers cached Mem: 725 666 59 0 132 287 -/+ buffers/cache: 245 479 Swap: 996 0 996 |
仔细看看,我的系统当中有 725MB 左右的实体内存,我的 swap 有 1GB 左右,那我使用 free -m 以 MBytes 来显示时,就会出现上面的资讯。Mem 那一行显示的是实体内存的量,Swap 则是虚拟内存的量。 total 是总量, used 是已被使用的量, free 则是剩余可用的量。后面的 shared/buffers/cached 则是在已被使用的量当中,用来作为缓冲及缓存的量。
仔细的看到范例一的输出喔,我们的 Linux 测试用主机是很平凡的,根本没有什么工作,但是,我的实体内存是几乎被用光光的情况呢!不过,至少有 132MB 用在缓冲记忆 (buffers) 工作,287MB 则用在缓存 (cached) 工作,也就是说,系统是『很有效率的将所有的内存用光光』,目的是为了让系统的存取效能加速啦!
很多朋友都会问到这个问题『我的系统明明很轻松,为何内存会被用光光?』现在了了吧?被用光是正常的!而需要注意的反而是 swap 的量。一般来说, swap 最好不要被使用,尤其 swap 最好不要被使用超过 20% 以上,如果您发现 swap 的用量超过 20% ,那么,最好还是买实体内存来插吧!因为, Swap 的效能跟实体内存实在差很多,而系统会使用到 swap ,绝对是因为实体内存不足了才会这样做的!如此,了解吧!
Tips: Linux 系统为了要加速系统效能,所以会将最常使用到的或者是最近使用到的文件数据缓存 (cache) 下来,这样未来系统要使用该文件时,就直接由内存中搜寻取出,而不需要重新读取硬盘,速度上面当然就加快了!因此,实体内存被用光是正常的喔! |
[root@www ~]# uname [-asrmpi] 选项与参数: -a :所有系统相关的资讯,包括底下的数据都会被列出来; -s :系统核心名称 -r :核心的版本 -m :本系统的硬件名称,例如 i686 或 x86_64 等; -p :CPU 的类型,与 -m 类似,只是显示的是 CPU 的类型! -i :硬件的平台 (ix86) 范例一:输出系统的基本资讯 [root@www ~]# uname -a Linux www.vbird.tsai 2.6.18-92.el5 #1 SMP Tue Jun 10 18:49:47 EDT 2008 i686 i686 i386 GNU/Linux |
这个咚咚我们前面使用过很多次了喔!uname 可以列出目前系统的核心版本、主要硬件平台以及 CPU 类型等等的资讯。以上面范例一的状态来说,我的 Linux 主机使用的核心名称为 Linux,而主机名称为 www.vbird.tsai,核心的版本为2.6.18-92.el5 ,该核心版本创建的日期为 2008/6/10,适用的硬件平台为 i386 以上等级的硬件平台喔。
这个命令很单纯呢!就是显示出目前系统已经启动多久的时间,以及 1, 5, 15 分钟的平均负载就是了。还记得 top 吧?没错啦!这个 uptime 可以显示出 top 画面的最上面一行!
[root@www ~]# uptime 15:39:13 up 8 days, 14:52, 1 user, load average: 0.00, 0.00, 0.00 # top 这个命令已经谈过相关资讯,不再聊! |
这个 netstat 也是挺好玩的,其实这个命令比较常被用在网络的监控方面,不过,在程序管理方面也是需要了解的啦!这个命令的运行如下所示:基本上, netstat 的输出分为两大部分,分别是网络与系统自己的程序相关性部分:
[root@www ~]# netstat -[atunlp] 选项与参数: -a :将目前系统上所有的连线、监听、Socket 数据都列出来 -t :列出 tcp 网络封包的数据 -u :列出 udp 网络封包的数据 -n :不以程序的服务名称,以埠号 (port number) 来显示; -l :列出目前正在网络监听 (listen) 的服务; -p :列出该网络服务的程序 PID 范例一:列出目前系统已经创建的网络连线与 unix socket 状态 [root@www ~]# netstat Active Internet connections (w/o servers) <==与网络较相关的部分 Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 132 192.168.201.110:ssh 192.168.:vrtl-vmf-sa ESTABLISHED Active UNIX domain sockets (w/o servers) <==与本机的程序自己的相关性(非网络) Proto RefCnt Flags Type State I-Node Path unix 20 [ ] DGRAM 9153 /dev/log unix 3 [ ] STREAM CONNECTED 13317 /tmp/.X11-unix/X0 unix 3 [ ] STREAM CONNECTED 13233 /tmp/.X11-unix/X0 unix 3 [ ] STREAM CONNECTED 13208 /tmp/.font-unix/fs7100 ....(中间省略).... |
在上面的结果当中,显示了两个部分,分别是网络的连线以及 linux 上面的 socket 程序相关性部分。我们先来看看网际网络连线情况的部分:
我们看上面仅有一条连线的数据,他的意义是:『透过 TCP 封包的连线,远程的 192.168.:vrtl.. 连线到本地端的192.168.201.110:ssh ,这条连线状态是创建 (ESTABLISHED) 的状态!』至於更多的网络环境说明,就得到鸟哥的另一本服务器篇查阅罗!
除了网络上的连线之外,其实 Linux 系统上面的程序是可以接收不同程序所发送来的资讯,那就是 Linux 上头的插槽档 (socket file)。我们在第六章的文件种类有稍微提到 socket 文件,但当时未谈到程序的概念,所以没有深入谈论。socket file 可以沟通两个程序之间的资讯,因此程序可以取得对方传送过来的数据。由於有 socket file,因此类似 X Window 这种需要透过网络连接的软件,目前新版的 distributions 就以 socket 来进行窗口介面的连线沟通了。上表中 socket file 的输出栏位有:
以上表的输出为例,最后那三行在 /tmp/.xx 底下的数据,就是 X Window 窗口介面的相关程序啦!而 PATH 指向的就是这些程序要交换数据的插槽文件罗!好!那么 netstat 可以帮我们进行什么任务呢?很多喔!我们先来看看,利用 netstat 去看看我们的哪些程序有启动哪些网络的『后门』呢?
范例二:找出目前系统上已在监听的网络连线及其 PID [root@www ~]# netstat -tlnp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:2208 0.0.0.0:* LISTEN 4566/hpiod tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 4328/portmap tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 4597/cupsd tcp 0 0 0.0.0.0:728 0.0.0.0:* LISTEN 4362/rpc.statd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 4629/sendmail: tcp 0 0 127.0.0.1:2207 0.0.0.0:* LISTEN 4571/python tcp 0 0 :::22 :::* LISTEN 4586/sshd # 除了可以列出监听网络的介面与状态之外,最后一个栏位还能够显示此服务的 # PID 号码以及程序的命令名称喔!例如最后一行的 4586 就是该 PID 范例三:将上述的本地端 127.0.0.1:631 那个网络服务关闭的话? [root@www ~]# kill -9 4597 [root@www ~]# killall -9 cupsd |
很多朋友常常有疑问,那就是,我的主机目前到底开了几个门(ports)!其实,不论主机提供什么样的服务,一定必须要有相对应的 program 在主机上面运行才行啊!举例来说,我们鸟园的 Linux 主机提供的就是 WWW 服务,那么我的主机当然有一个程序在提供 WWW 的服务啊!那就是 Apache 这个软件所提供的啦! ^_^。所以,当我运行了这个程序之后,我的系统自然就可以提供 WWW 的服务了。那如何关闭啊?就关掉该程序所触发的那个程序就好了!例如上面的范例三所提供的例子啊! ^_^
系统在启动的时候,核心会去侦测系统的硬件,你的某些硬件到底有没有被捉到,那就与这个时候的侦测有关。但是这些侦测的过程要不是没有显示在萤幕上,就是很飞快的在萤幕上一闪而逝!能不能把核心侦测的信息捉出来瞧瞧?可以的,那就使用 dmesg 吧!
所有核心侦测的信息,不管是启动时候还是系统运行过程中,反正只要是核心产生的信息,都会被记录到内存中的某个保护区段。dmesg 这个命令就能够将该区段的信息读出来的!因为信息实在太多了,所以运行时可以加入这个管线命令『 | more 』来使画面暂停!
范例一:输出所有的核心启动时的资讯 [root@www ~]# dmesg | more 范例二:搜寻启动的时候,硬盘的相关资讯为何? [root@www ~]# dmesg | grep -i hd ide0: BM-DMA at 0xd800-0xd807, BIOS settings: hda:DMA, hdb:DMA ide1: BM-DMA at 0xd808-0xd80f, BIOS settings: hdc:pio, hdd:pio hda: IC35L040AVER07-0, ATA DISK drive hdb: ASUS DRW-2014S1, ATAPI CD/DVD-ROM drive hda: max request size: 128KiB ....(底下省略).... |
由范例二就知道我这部主机的硬盘的格式是什么了吧!没错啦!还可以查阅能不能找到网络卡喔!网络卡的代号是 eth ,所以,直接输入 dmesg | grep -i eth 试看看呢!
如果你想要动态的了解一下系统资源的运行,那么这个 vmstat 确实可以玩一玩!vmstat 可以侦测『 CPU /内存 / 磁碟输入输出状态 』等等,如果你想要了解一部繁忙的系统到底是哪个环节最累人,可以使用 vmstat 分析看看。底下是常见的选项与参数说明:
[root@www ~]# vmstat [-a] [延迟 [总计侦测次数]] <==CPU/内存等资讯 [root@www ~]# vmstat [-fs] <==内存相关 [root@www ~]# vmstat [-S 单位] <==配置显示数据的单位 [root@www ~]# vmstat [-d] <==与磁碟有关 [root@www ~]# vmstat [-p 分割槽] <==与磁碟有关 选项与参数: -a :使用 inactive/active(活跃与否) 取代 buffer/cache 的内存输出资讯; -f :启动到目前为止,系统复制 (fork) 的程序数; -s :将一些事件 (启动至目前为止) 导致的内存变化情况列表说明; -S :后面可以接单位,让显示的数据有单位。例如 K/M 取代 bytes 的容量; -d :列出磁碟的读写总量统计表 -p :后面列出分割槽,可显示该分割槽的读写总量统计表 范例一:统计目前主机 CPU 状态,每秒一次,共计三次! [root@www ~]# vmstat 1 3 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 28 61540 137000 291960 0 0 4 5 38 55 0 0 100 0 0 0 0 28 61540 137000 291960 0 0 0 0 1004 50 0 0 100 0 0 0 0 28 61540 137000 291964 0 0 0 0 1022 65 0 0 100 0 0 |
利用 vmstat 甚至可以进行追踪喔!你可以使用类似『 vmstat 5 』代表每五秒钟升级一次,且无穷的升级!直到你按下 [ctrl]-c 为止。如果你想要即时的知道系统资源的运行状态,这个命令就不能不知道!那么上面的表格各项栏位的意义为何?基本说明如下:
由於鸟哥的机器是测试机,所以并没有什么 I/O 或者是 CPU 忙碌的情况。如果改天你的服务器非常忙碌时,记得使用 vmstat 去看看,到底是哪个部分的资源被使用的最为频繁!一般来说,如果 I/O 部分很忙碌的话,你的系统会变的非常慢!让我们再来看看,那么磁碟的部分该如何观察:
范例二:系统上面所有的磁碟的读写状态 [root@www ~]# vmstat -d disk- ------------reads------------ ------------writes----------- -----IO------ total merged sectors ms total merged sectors ms cur sec ram0 0 0 0 0 0 0 0 0 0 0 ....(中间省略).... hda 144188 182874 6667154 7916979 151341 510244 8027088 15244705 0 848 hdb 0 0 0 0 0 0 0 0 0 0 |
详细的各栏位就请诸位大德查阅一下 man vmstat 罗!反正与读写有关啦!这样了解乎!
我们在第七章曾经谈到特殊权限的 SUID/SGID/SBIT,虽然第七章已经将这三种特殊权限作了详细的解释,不过,我们依旧要来探讨的是,那么到底这些权限对於你的『程序』是如何影响的?此外,程序可能会使用到系统资源,举例来说,磁碟就是其中一项资源。哪天你在 umount 磁碟时,系统老是出现『 device is busy 』的字样~到底是怎么回事啊?我们底下就来谈一谈这些和程序有关系的细节部分:
SUID 的权限其实与程序的相关性非常的大!为什么呢?先来看看 SUID 的程序是如何被一般使用者运行,且具有什么特色呢?
所以说,整个 SUID 的权限会生效是由於『具有该权限的程序被触发』,而我们知道一个程序被触发会变成程序,所以罗,运行者可以具有程序拥有者的权限就是在该程序变成程序的那个时候啦!第七章我们还没谈到程序的概念,所以你或许那时候会觉得很奇怪,为啥运行了 passwd 后你就具有 root 的权限呢?不都是一般使用者运行的吗?这是因为你在触发 passwd 后,会取得一个新的程序与 PID,该 PID 产生时透过 SUID 来给予该 PID 特殊的权限配置啦!我们使用 dmtsai 登陆系统且运行 passwd 后,透过工作控制来理解一下!
[dmtsai@www ~]$ passwd Changing password for user dmtsai. Changing password for dmtsai (current) UNIX password: <==这里按下 [ctrl]-z 并且按下 [enter] [1]+ Stopped passwd [dmtsai@www ~]$ pstree -u init-+-acpid ....(中间省略).... |-sshd---sshd---sshd(dmtsai)---bash-+-more | |-passwd(root) | `-pstree ....(底下省略).... |
从上表的结果我们可以发现,底线的部分是属於 dmtsai 这个一般帐号的权限,特殊字体的则是 root 的权限!但你看到了, passwd 确实是由 bash 衍生出来的!不过就是权限不一样!透过这样的解析,你也会比较清楚为何不同程序所产生的权限不同了吧!这是由於『SUID 程序运行过程中产生的程序』的关系啦!
那么既然 SUID/SGID 的权限是比较可怕的,您该如何查询整个系统的 SUID/SGID 的文件呢?应该是还不会忘记吧?使用 find 即可啊!
find / -perm +6000
其实,我们之前提到的所谓的程序都是在内存当中嘛!而内存当中的数据又都是写入到/proc/* 这个目录下的,所以罗,我们当然可以直接观察 /proc 这个目录当中的文件啊!如果你观察过 /proc 这个目录的话,应该会发现他有点像这样:
[root@www ~]# ll /proc dr-xr-xr-x 5 root root 0 Mar 11 08:46 1 dr-xr-xr-x 5 root root 0 Mar 11 00:46 10 dr-xr-xr-x 5 root root 0 Mar 11 00:46 11 ....(中间省略).... -r--r--r-- 1 root root 0 Mar 20 12:11 uptime -r--r--r-- 1 root root 0 Mar 20 12:11 version -r--r--r-- 1 root root 0 Mar 20 12:11 vmstat -r--r--r-- 1 root root 0 Mar 20 12:11 zoneinfo |
基本上,目前主机上面的各个程序的 PID 都是以目录的型态存在於 /proc 当中。举例来说,我们启动所运行的第一支程序 init 他的 PID 是 1 ,这个 PID 的所有相关资讯都写入在 /proc/1/* 当中!若我们直接观察 PID 为 1 的数据好了,他有点像这样:
[root@www ~]# ll /proc/1 dr-xr-xr-x 2 root root 0 Mar 12 11:04 attr -r-------- 1 root root 0 Mar 17 14:32 auxv -r--r--r-- 1 root root 0 Mar 17 14:32 cmdline <==就是命令串 -rw-r--r-- 1 root root 0 Mar 17 14:32 coredump_filter -r--r--r-- 1 root root 0 Mar 17 14:32 cpuset lrwxrwxrwx 1 root root 0 Mar 17 14:32 cwd -> / -r-------- 1 root root 0 Mar 17 14:32 environ <==一些环境变量 lrwxrwxrwx 1 root root 0 Mar 17 14:32 exe -> /sbin/init <==实际运行的命令 ....(以下省略).... |
里面的数据还挺多的,不过,比较有趣的其实是两个文件,分别是:
很有趣吧!如果你查阅一下 cmdline 的话,就会发现:
[root@www ~]# cat /proc/1/cmdline
init [5]
|
就是这个命令、选项与参数启动 init 的啦!这还是跟某个特定的 PID 有关的内容呢,如果是针对整个 Linux 系统相关的参数呢?那就是在 /proc 目录底下的文件啦!相关的文件与对应的内容是这样的:(注3)
档名 | 文件内容 |
/proc/cmdline | 加载 kernel 时所下达的相关参数!查阅此文件,可了解系统是如何启动的! |
/proc/cpuinfo | 本机的 CPU 的相关资讯,包含时脉、类型与运算功能等 |
/proc/devices | 这个文件记录了系统各个主要装置的主要装置代号,与 mknod 有关呢! |
/proc/filesystems | 目前系统已经加载的文件系统罗! |
/proc/interrupts | 目前系统上面的 IRQ 分配状态。 |
/proc/ioports | 目前系统上面各个装置所配置的 I/O 位址。 |
/proc/kcore | 这个就是内存的大小啦!好大对吧!但是不要读他啦! |
/proc/loadavg | 还记得 top 以及 uptime 吧?没错!上头的三个平均数值就是记录在此! |
/proc/meminfo | 使用 free 列出的内存资讯,嘿嘿!在这里也能够查阅到! |
/proc/modules | 目前我们的 Linux 已经加载的模块列表,也可以想成是驱动程序啦! |
/proc/mounts | 系统已经挂载的数据,就是用 mount 这个命令呼叫出来的数据啦! |
/proc/swaps | 到底系统挂加载的内存在哪里?呵呵!使用掉的 partition 就记录在此啦! |
/proc/partitions | 使用 fdisk -l 会出现目前所有的 partition 吧?在这个文件当中也有纪录喔! |
/proc/pci | 在 PCI 汇流排上面,每个装置的详细情况!可用 lspci 来查阅! |
/proc/uptime | 就是用 uptime 的时候,会出现的资讯啦! |
/proc/version | 核心的版本,就是用 uname -a 显示的内容啦! |
/proc/bus/* | 一些汇流排的装置,还有 U盘 的装置也记录在此喔! |
其实,上面这些文件鸟哥在此建议您可以使用 cat 去查阅看看,不必深入了解,不过,观看过文件内容后,毕竟会比较有感觉啦!如果未来您想要自行撰写某些工具软件,那么这个目录底下的相关文件可能会对您有点帮助的喔!
其实还有一些与程序相关的命令可以值得参考与应用的,我们来谈一谈:
有的时候我想要知道我的程序到底在这次启动过程中开启了多少文件,可以利用 fuser 来观察啦!举例来说,你如果卸载时发现系统通知:『 device is busy 』,那表示这个文件系统正在忙碌中,表示有某支程序有利用到该文件系统啦!那么你就可以利用 fuser 来追踪罗!fuser 语法有点像这样:
[root@www ~]# fuser [-umv] [-k [i] [-signal]] file/dir 选项与参数: -u :除了程序的 PID 之外,同时列出该程序的拥有者; -m :后面接的那个档名会主动的上提到该文件系统的最顶层,对 umount 不成功很有效! -v :可以列出每个文件与程序还有命令的完整相关性! -k :找出使用该文件/目录的 PID ,并试图以 SIGKILL 这个讯号给予该 PID; -i :必须与 -k 配合,在删除 PID 之前会先询问使用者意愿! -signal:例如 -1 -15 等等,若不加的话,默认是 SIGKILL (-9) 罗! 范例一:找出目前所在目录的使用 PID/所属帐号/权限 为何? [root@www ~]# fuser -uv . USER PID ACCESS COMMAND .: root 20639 ..c.. (root)bash |
看到输出的结果没?他说『.』底下有个 PID 为 20639 的程序,该程序属於 root 且命令为 bash 。比较有趣的是那个 ACCESS 的项目,那个项目代表的意义为:
那如果你想要查阅某个文件系统底下有多少程序正在占用该文件系统时,那个 -m 的选项就很有帮助了!鸟哥的测试主机仅有分割出 /, /boot, /home ,所以无法进行测试。不过好在还有个 /proc 的虚拟文件系统,让我们来了解一下这个 /proc 的文件系统有多少程序正在利用他吧!
范例二:找到所有使用到 /proc 这个文件系统的程序吧! [root@www ~]# fuser -uv /proc # 不会显示任何数据,因为没有任何程序会去使用 /proc 这个目录啊! # 会被用到的是 /proc 底下的文件啦!所以你应该要这样做: [root@www ~]# fuser -mvu /proc USER PID ACCESS COMMAND /proc: root 4289 f.... (root)klogd root 4555 f.... (root)acpid haldaemon 4758 f.... (haldaemon)hald root 4977 F.... (root)Xorg # 有这几支程序在进行 /proc 文件系统的存取喔!这样清楚了吗? |
既然可以针对整个文件系统,那么能不能仅针对单一文件啊?当然可以罗!看一下底下的案例先:
范例三:找到 /var 底下属於 FIFO 类型的文件,并且找出存取该文件的程序 [root@www ~]# find /var -type p /var/gdm/.gdmfifo <==我们针对这玩意即可! /var/run/autofs.fifo-misc /var/run/autofs.fifo-net [root@www ~]# fuser -uv /var/gdm/.gdmfifo USER PID ACCESS COMMAND /var/gdm/.gdmfifo: root 4892 F.... (root)gdm-binary 范例四:同范例三,但试图删除该 PID?且『不要』删除喔! [root@www ~]# fuser -ki /var/gdm/.gdmfifo /var/gdm/.gdmfifo: 4892 Kill process 4892 ? (y/N) n |
如何?很有趣的一个命令吧!透过这个 fuser 我们可以找出使用该文件、目录的程序,藉以观察的啦!他的重点与 ps, pstree 不同。 fuser 可以让我们了解到某个文件 (或文件系统) 目前正在被哪些程序所利用!
相对於 fuser 是由文件或者装置去找出使用该文件或装置的程序,反过来说,如何查出某个程序开启或者使用的文件与装置呢?呼呼!那就是使用 lsof 罗~
[root@www ~]# lsof [-aUu] [+d] 选项与参数: -a :多项数据需要『同时成立』才显示出结果时! -U :仅列出 Unix like 系统的 socket 文件类型; -u :后面接 username,列出该使用者相关程序所开启的文件; +d :后面接目录,亦即找出某个目录底下已经被开启的文件! 范例一:列出目前系统上面所有已经被开启的文件与装置: [root@www ~]# lsof COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME init 1 root cwd DIR 3,2 4096 2 / init 1 root rtd DIR 3,2 4096 2 / init 1 root txt REG 3,2 38620 1426405 /sbin/init ....(底下省略).... # 注意到了吗?是的,在默认的情况下, lsof 会将目前系统上面已经开启的 # 文件全部列出来~所以,画面多的吓人啊!您可以注意到,第一个文件 init 运行的 # 地方就在根目录,而根目录,嘿嘿!所在的 inode 也有显示出来喔! 范例二:仅列出关於 root 的所有程序开启的 socket 文件 [root@www ~]# lsof -u root -a -U COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME udevd 400 root 3u unix 0xedd4cd40 1445 socket auditd 4256 root 7u unix 0xedd4c380 9081 socket audispd 4258 root 0u unix 0xedd4c1e0 9080 socket # 注意到那个 -a 吧!如果你分别输入 lsof -u root 及 lsof -U ,会有啥资讯? # 使用 lsof -u root -U 及 lsof -u root -a -U ,呵呵!都不同啦! # -a 的用途就是在解决同时需要两个项目都成立时啊! ^_^ 范例三:请列出目前系统上面所有的被启动的周边装置 [root@www ~]# lsof +d /dev COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME init 1 root 10u FIFO 0,16 1147 /dev/initctl udevd 400 root 0u CHR 1,3 1420 /dev/null udevd 400 root 1u CHR 1,3 1420 /dev/null udevd 400 root 2u CHR 1,3 1420 /dev/null # 看吧!因为装置都在 /dev 里面嘛!所以罗,使用搜寻目录即可啊! 范例四:秀出属於 root 的 bash 这支程序所开启的文件 [root@www ~]# lsof -u root | grep bash bash 20639 root cwd DIR 3,2 4096 648321 /root bash 20639 root rtd DIR 3,2 4096 2 / bash 20639 root txt REG 3,2 735004 1199424 /bin/bash bash 20639 root mem REG 3,2 46680 64873 /lib/libnss_files-2.5.so ....(底下省略).... |
这个命令可以找出您想要知道的某个程序是否有激活哪些资讯?例如上头提到的范例四的运行结果呢! ^_^
[root@www ~]# pidof [-sx] program_name 选项与参数: -s :仅列出一个 PID 而不列出所有的 PID -x :同时列出该 program name 可能的 PPID 那个程序的 PID 范例一:列出目前系统上面 init 以及 syslogd 这两个程序的 PID [root@www ~]# pidof init syslogd 1 4286 # 理论上,应该会有两个 PID 才对。上面的显示也是出现了两个 PID 喔。 # 分别是 init 及 syslogd 这两支程序的 PID 啦。 |
很简单的用法吧,透过这个 pidof 命令,并且配合 ps aux 与正规表示法,就可以很轻易的找到您所想要的程序内容了呢。
在进入了 CentOS 5.x 之后,SELinux 已经是个非常完备的核心模块了!CentOS 5.x 提供了很多管理 SELinux 的命令与机制,因此在整体架构上面比以前的版本要单纯且容易操作管理!所以,在这一版以后,我们建议大家千万不要关掉 SELinux 这玩意儿!让我们来仔细的玩玩这家伙吧!
什么是 SELinux 呢?其实他是『 Security Enhanced Linux 』的缩写,字面上的意义就是安全强化的 Linux 之意!那么所谓的『安全强化』是强化哪个部分?是网络资安还是权限管理?底下就让我们来谈谈吧!
SELinux 是由美国国家安全局 (NSA) 开发的,当初开发这玩意儿的目的是因为很多企业界发现,通常系统出现问题的原因大部分都在於『内部员工的资源误用』所导致的,实际由外部发动的攻击反而没有这么严重。那么什么是『员工资源误用』呢?举例来说,如果有个不是很懂系统的系统管理员为了自己配置的方便,将网页所在目录 /var/www/html/ 的权限配置为 drwxrwxrwx 时,你觉得会有什么事情发生?
现在我们知道所有的系统资源都是透过程序来进行存取的,那么 /var/www/html/ 如果配置为 777 ,代表所有程序均可对该目录存取,万一你真的有启动 WWW 服务器软件,那么该软件所触发的程序将可以写入该目录,而该程序却是对整个 Internet 提供服务的!只要有心人接触到这支程序,而且该程序刚好又有提供使用者进行写入的功能,那么外部的人很可能就会对你的系统写入些莫名其妙的东西!那可真是不得了!一个小小的 777 问题可是大大的!
为了控管这方面的权限与程序的问题,所以美国国家安全局就著手处理操作系统这方面的控管。由於 Linux 是自由软件,程序码都是公开的,因此她们便使用 Linux 来作为研究的目标,最后更将研究的结果整合到 Linux 核心里面去,那就是 SELinux 啦!所以说, SELinux 是整合到核心的一个模块喔!更多的 SELinux 相关说明可以参考:
这也就是说:其实 SELinux 是在进行程序、文件等细部权限配置依据的一个核心模块!由於启动网络服务的也是程序,因此刚好也能够控制网络服务能否存取系统资源的一道关卡!所以,在讲到 SELinux 对系统的存取控制之前,我们得先来回顾一下之前谈到的系统文件权限与使用者之间的关系。因为先谈完这个你才会知道为何需要 SELinux 的啦!
我们第十四章的内容,知道系统的帐号主要分为系统管理员 (root) 与一般用户,而这两种身份能否使用系统上面的文件资源则与 rwx 的权限配置有关。不过你要注意的是,各种权限配置对 root 是无效的。因此,当某个程序想要对文件进行存取时,系统就会根据该程序的拥有者/群组,并比对文件的权限,若通过权限检查,就可以存取该文件了。
这种存取文件系统的方式被称为『自主式存取控制 (Discretionary Access Control, DAC)』,基本上,就是依据程序的拥有者与文件资源的 rwx 权限来决定有无存取的能力。不过这种 DAC 的存取控制有几个困扰,那就是:
这些问题是非常严重的!尤其是当你的系统是被某些漫不经心的系统管理员所掌控时!她们甚至觉得目录权限调为 777 也没有什么了不起的危险哩...
现在我们知道 DAC 的困扰就是当使用者取得程序后,他可以藉由这支程序与自己默认的权限来处理他自己的文件资源。万一这个使用者对 Linux 系统不熟,那就很可能会有资源误用的问题产生。为了避免 DAC 容易发生的问题,因此 SELinux 导入了委任式存取控制 (Mandatory Access Control, MAC) 的方法!
委任式存取控制 (MAC) 有趣啦!他可以针对特定的程序与特定的文件资源来进行权限的控管!也就是说,即使你是 root ,那么在使用不同的程序时,你所能取得的权限并不一定是 root ,而得要看当时该程序的配置而定。如此一来,我们针对控制的『主体』变成了『程序』而不是使用者喔!此外,这个主体程序也不能任意使用系统文件资源,因为每个文件资源也有针对该主体程序配置可取用的权限!如此一来,控制项目就细的多了!但整个系统程序那么多、文件那么多,一项一项控制可就没完没了!所以 SELinux 也提供一些默认的政策 (Policy) ,并在该政策内提供多个守则 (rule) ,让你可以选择是否激活该控制守则!
在委任式存取控制的配置下,我们的程序能够活动的空间就变小了!举例来说, WWW 服务器软件的达成程序为 httpd 这支程序,而默认情况下, httpd 仅能在 /var/www/ 这个目录底下存取文件,如果 httpd 这个程序想要到其他目录去存取数据时,除了守则配置要开放外,目标目录也得要配置成 httpd 可读取的模式 (type) 才行喔!限制非常多!所以,即使不小心 httpd 被 cracker 取得了控制权,他也无权浏览 /etc/shadow 等重要的配置档喔!
再次的重复说明一下,SELinux 是透过 MAC 的方式来控管程序,他控制的主体是程序,而目标则是该程序能否读取的『文件资源』!所以先来说明一下这些咚咚的相关性啦!(注4)
上图的重点在『主体』如何取得『目标』的资源存取权限!由上图我们可以发现,主体程序必须要通过 SELinux 政策内的守则放行后,就可以与目标资源进行安全性本文的比对,若比对失败则无法存取目标,若比对成功则可以开始存取目标。问题是,最终能否存取目标还是与文件系统的 rwx 权限配置有关喔!如此一来,加入了 SELinux 之后,出现权限不符的情况时,你就得要一步一步的分析可能的问题了!
CentOS 5.x 已经帮我们制订好非常多的守则了,这部份你只要知道如何开启/关闭某项守则的放行与否即可。那个安全性本文比较麻烦!因为你可能需要自行配置文件的安全性本文呢!为何需要自行配置啊?举例来说,你不也常常进行文件的 rwx 的重新配置吗?这个安全性本文你就将他想成 SELinux 内必备的 rwx 就是了!这样比较好理解啦。
安全性本文存在於主体程序中与目标文件资源中。程序在内存内,所以安全性本文可以存入是没问题。那文件的安全性本文是记录在哪里呢?事实上,安全性本文是放置到文件的 inode内的,因此主体程序想要读取目标文件资源时,同样需要读取 inode ,这 inode 内就可以比对安全性本文以及 rwx 等权限值是否正确,而给予适当的读取权限依据。
那么安全性本文到底是什么样的存在呢?我们先来看看 /root 底下的文件的安全性本文好了。观察安全性本文可使用『 ls -Z 』去观察如下:(注意:你必须已经启动了 SELinux 才行!若尚未启动,这部份请稍微看过一遍即可。底下会介绍如何启动 SELinux 喔!)
[root@www ~]# ls -Z drwxr-xr-x root root root:object_r:user_home_t Desktop -rw-r--r-- root root root:object_r:user_home_t install.log -rw-r--r-- root root root:object_r:user_home_t install.log.syslog # 上述特殊字体的部分,就是安全性本文的内容! |
如上所示,安全性本文主要用冒号分为三个栏位,这三个栏位的意义为:
Identify:role:type 身份识别:角色:类型 |
这三个栏位的意义仔细的说明一下吧:
那么这三个栏位如何利用呢?首先我们来瞧瞧主体程序在这三个栏位的意义为何!透过身份识别与角色栏位的定义,我们可以约略知道某个程序所代表的意义喔!基本上,这些对应数据在 targeted 政策下的对应如下:
身份识别 | 角色 | 该对应在 targeted 的意义 |
root | system_r | 代表供 root 帐号登陆时所取得的权限 |
system_u | system_r | 由於为系统帐号,因此是非交谈式的系统运行程序 |
user_u | system_r | 一般可登陆使用者的程序罗! |
但就如上所述,其实最重要的栏位是类型栏位,主体与目标之间是否具有可以读写的权限,与程序的 domain 及文件的type 有关!这两者的关系我们可以使用达成 WWW 服务器功能的 httpd 这支程序与 /var/www/html 这个网页放置的目录来说明。首先,看看这两个咚咚的安全性本文内容先:
[root@www ~]# ll -Zd /usr/sbin/httpd /var/www/html -rwxr-xr-x root root system_u:object_r:httpd_exec_t /usr/sbin/httpd drwxr-xr-x root root system_u:object_r:httpd_sys_content_t /var/www/html # 两者的角色栏位都是 object_r ,代表都是文件!而 httpd 属於 httpd_exec_t 类型, # /var/www/html 则属於 httpd_sys_content_t 这个类型! |
httpd 属於 httpd_exec_t 这个可以运行的类型,而 /var/www/html 则属於 httpd_sys_content_t 这个可以让httpd 领域 (domain) 读取的类型。文字看起来不太容易了解吧!我们使用图示来说明这两者的关系!
上图的意义我们可以这样看的:
上述的流程告诉我们几个重点,第一个是政策内需要制订详细的 domain/type 相关性;第二个是若文件的 type 配置错误,那么即使权限配置为 rwx 全开的 777 ,该主体程序也无法读取目标文件资源的啦!不过如此一来,也就可以避免使用者将他的家目录配置为 777 时所造成的权限困扰。
并非所有的 Linux distributions 都支持 SELinux 的,所以你必须要先观察一下你的系统版本为何!鸟哥这里介绍的 CentOS 5.x 本身就有支持 SELinux 啦!所以你不需要自行编译 SELinux 到你的 Linux 核心中!目前 SELinux 支持三种模式,分别如下:
那你怎么知道目前的 SELinux 模式呢?就透过 getenforce 吧!
[root@www ~]# getenforce Enforcing <==诺!就显示出目前的模式为 Enforcing 罗! |
另外,我们又如何知道 SELinux 的政策 (Policy) 为何呢?这时可以使用 sestatus 来观察:
[root@www ~]# sestatus [-vb] 选项与参数: -v :检查列於 /etc/sestatus.conf 内的文件与程序的安全性本文内容; -b :将目前政策的守则布林值列出,亦即某些守则 (rule) 是否要启动 (0/1) 之意; 范例一:列出目前的 SELinux 使用哪个政策 (Policy)? [root@www ~]# sestatus SELinux status: enabled <==是否启动 SELinux SELinuxfs mount: /selinux <==SELinux 的相关文件数据挂载点 Current mode: enforcing <==目前的模式 Mode from config file: enforcing <==配置档指定的模式 Policy version: 21 Policy from config file: targeted <==目前的政策为何? |
如上所示,目前是启动的,而且是 Enforcing 模式,而由配置档查询得知亦为 Enforcing 模式。此外,目前的默认政策为 targeted 这一个。你应该要有疑问的是, SELinux 的配置档是哪个文件啊?其实就是 /etc/selinux/config 这个文件喔!我们来看看内容:
[root@www ~]# vi /etc/selinux/config SELINUX=enforcing <==调整 enforcing|disabled|permissive SELINUXTYPE=targeted <==目前仅有 targeted 与 strict |
上面是默认的政策与启动的模式!你要注意的是,如果改变了政策则需要重新启动;如果由 enforcing 或 permissive改成 disabled ,或由 disabled 改成其他两个,那也必须要重新启动。这是因为 SELinux 是整合到核心里面去的,你只可以在 SELinux 运行下切换成为强制 (enforcing) 或宽容 (permissive) 模式,不能够直接关闭 SELinux 的!同时,由 SELinux 关闭 (disable) 的状态到开启的状态也需要重新启动啦!所以,如果刚刚你发现 getenforce 出现 disabled 时,请到上述文件修改成为 enforcing 吧!
所以,如果你要启动 SELinux 的话,请将上述的 SELINUX=enforcing 配置妥当,并且指定 SELINUXTYPE=targeted 这一个配置,并且到 /boot/grub/menu.lst 这个文件去,看看核心有无关闭 SELinux 了呢?
[root@www ~]# vi /boot/grub/menu.lst default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title CentOS (2.6.18-92.el5) root (hd0,0) kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet |
请注意到上面特殊字体的那一行,确认 kernel 后面不可以接『 selinux=0 』这个项目!因为 selinux=0 指定给核心时,则核心会自动的忽略 /etc/selinux/config 的配置值,而直接略过 SELinux 的加载,所以你的 SELinux 模式就会变成 disabled 啦!因为我们要启动,所以这里得要确认不存在 selinux=0 才行!切记切记!如果一切配置妥当,接下来就是 reboot 重新启动吧!
不过你要注意的是,如果从 disable 转到启动 SELinux 的模式时,由於系统必须要针对文件写入安全性本文的资讯,因此启动过程会花费不少时间在等待重新写入 SELinux 安全性本文 (有时也称为 SELinux Label) ,而且在写完之后还得要再次的重新启动一次喔!你必须要等待粉长一段时间!等到下次启动成功后,再使用getenforce 或 sestatus来观察看看有否成功的启动到 Enforcing 的模式罗!
如果你已经在 Enforcing 的模式,但是可能由於一些配置的问题导致 SELinux 让某些服务无法正常的运行,此时你可以将 Enforcing 的模式改为宽容 (permissive) 的模式,让 SELinux 只会警告无法顺利连线的信息,而不是直接抵挡主体程序的读取权限。让 SELinux 模式在 enforcing 与 permissive 之间切换的方法为:
[root@www ~]# setenforce [0|1] 选项与参数: 0 :转成 permissive 宽容模式; 1 :转成 Enforcing 强制模式 范例一:将 SELinux 在 Enforcing 与 permissive 之间切换与观察 [root@www ~]# setenforce 0 [root@www ~]# getenforce Permissive [root@www ~]# setenforce 1 [root@www ~]# getenforce Enforcing |
不过请注意, setenforce 无法在 Disabled 的模式底下进行模式的切换喔!
由於 CentOS 5.x 默认使用 targeted 这个政策,而这个政策主要是在管理网络服务,本机端的程序则比较不受 SELinux 的管制。既然上头我们曾经举过 /usr/sbin/httpd 这个程序来当作范例,那么我们就使用 WWW 服务器来说明一下 SELinux 的运行方式吧。
首先,让我们启动 httpd 这支服务吧!要记得的是,一般服务启动的脚本会在 /etc/init.d/ 底下,所以我们可以这样启动与观察:
# 1. 先启动这个网络服务吧! [root@www ~]# /etc/init.d/httpd start 正在启动 httpd: [ 确定 ] # 2. 观察有无此程序,并且观察此程序的 SELinux 安全性本文数据 [root@www ~]# pstree | grep httpd |-httpd---8*[httpd] <==httpd 会产生很多子程序来负责网络服务喔! [root@www ~]# ps aux -Z |grep http root:system_r:httpd_t root 24089 0.2 1.2 22896 9256 ? Ss 16:06 0:00 /usr/sbin/httpd root:system_r:httpd_t apache 24092 0.0 0.6 22896 4752 ? S 16:06 0:00 /usr/sbin/httpd root:system_r:httpd_t apache 24093 0.0 0.6 22896 4752 ? S 16:06 0:00 /usr/sbin/httpd ....(后面省略).... |
ps -Z 这个『 -Z 』的选项可以让我们查阅程序的安全性本文!其他相关的程序说明请自行查阅本章上面各节的内容。我们可以发现这整个程序的 domain 是 httpd_t 这个咚咚喔!再来我们来处理一下首页的数据先。由於首页是放置到 /var/www/html,且档名应该要是『 index.html 』,因此我们可以这样简单的制作首页:
[root@www ~]# echo "This is my first web page." > /var/www/html/index.html
|
接下来,如果你在浏览器上面输入『 http://127.0.0.1 』应该会看到如下的画面才对!
此时你的浏览器会透过 httpd 这个程序拥有的 httpd_t 这个 domain 去读取 /var/www/html/index.html 这个文件的!先来看看这个文件的权限与 SELinux 的安全性本文数据:
[root@www ~]# ll -Z /var/www/html/index.html -rw-r--r-- root root root:object_r:httpd_sys_content_t /var/www/html/index.html |
权限是 apache 可以读取的 r 标志,而 SELinux 则是 httpd_sys_content_t 的类型 (type),也是 httpd_t 能读取的哩!那么为何 httpd_t 可以读取呢?因为 targeted 政策里面有配置嘛!关於政策配置的查询我们可以在后续跟大家作介绍,这里先了解一下即可。
让我们来了解一下什么是错误的安全性本文配置好了!现在,我们将重要的网页数据在 root 的家目录底下制作!配置如下:
# 1. 先在 root 的家目录建置所需的首页: [root@www ~]# echo "My 2nd web page..." > index.html # 2. 将首页 index.html 『搬移』到 /var/www/html 目录去: [root@www ~]# rm /var/www/html/index.html [root@www ~]# mv index.html /var/www/html # 这个测试的重点在 mv 这个命令的处理上!务必使用 mv 喔! |
等到上述的动作都做完后,如果在浏览器输入 http://127.0.0.1/index.html ,你应该会想到画面会出现我们想要的『 My 2nd web page...』才对,但是结果却变成:
记得要在网址列指定 index.html 否则出现的会变成欢迎首页的画面。而萤幕上出现的错误信息是没有权限(You don't have permission...)。看看这个 /var/www/html/index.html 的权限吧!
[root@www ~]# ll -Z /var/www/html/index.html -rw-r--r-- root root root:object_r:user_home_t /var/www/html/index.html |
你会发现,权限是对的 (apache 使用者依旧可以读取),但是安全性本文内容却是使用者家目录呢!真是要命!这个使用者家目录默认可不能给 httpd_t 这个 domain 读取的!所以就产生错误啦!那该如何处置呢?
既然安全性本文是错的,那么就将他改回来即可嘛!怎么修改呢?可以透过两个命令喔!首先我们使用 chcon 来处理:
[root@www ~]# chcon [-R] [-t type] [-u user] [-r role] 文件 [root@www ~]# chcon [-R] --reference=范例档 文件 选项与参数: -R :连同该目录下的次目录也同时修改; -t :后面接安全性本文的类型栏位!例如 httpd_sys_content_t ; -u :后面接身份识别,例如 system_u; -r :后面街角色,例如 system_r; --reference=范例档:拿某个文件当范例来修改后续接的文件的类型! 范例一:将刚刚的 index.html 类型改为 httpd_sys_content_t 的类型 [root@www ~]# chcon -t httpd_sys_content_t /var/www/html/index.html [root@www ~]# ll -Z /var/www/html/index.html -rw-r--r-- root root root:object_r:httpd_sys_content_t /var/www/html/index.html # 瞧!这样就改回来啦! 范例二:以 /etc/passwd 为依据,将 index.html 修改成该类型 [root@www ~]# ll -Z /etc/passwd -rw-r--r-- root root system_u:object_r:etc_t /etc/passwd [root@www ~]# chcon --reference=/etc/passwd /var/www/html/index.html [root@www ~]# ll -Z /var/www/html/index.html -rw-r--r-- root root root:object_r:etc_t /var/www/html/index.html # 看看!是否与上面的 /etc/passwd 相同了!不过,这又是错误的安全性本文! # 先不要急著修改!我们来进行底下的另外一个命令处置看看! |
chcon 是透过直接指定的方式来处理安全性本文的类型数据。那我们知道其实系统默认的目录都有特殊的 SELinux 安全性本文,举例来说, /var/www/html 原本就是 httpd 可以读取的目录嘛!既然如此,那有没有可以使用默认的安全性本文来还原的方式?有的,那就是 restorecon 这玩意儿:
[root@www ~]# restorecon [-Rv] 文件或目录 选项与参数: -R :连同次目录一起修改; -v :将过程显示到萤幕上 范例一:将刚刚错误的 index.html 以默认的安全性本文改正过来 [root@www ~]# restorecon -Rv /var/www/html/index.html restorecon reset /var/www/html/index.html context system_u:object_r:etc_t:s0-> system_u:object_r:httpd_sys_content_t:s0 # 上面这两行其实是同一行喔!表示将 index.html 由 etc_t 改为 httpd_sys_content_t |
然后回到刚刚图 5.4.2 给他重读一下,嘿嘿!又可以看到正确的内容啦!这个过程完全没有动到 rwx 权限,因为该权限本来就是对的!而错的部分是在於 SELinux 的安全性本文当中那个类型 (type) 配置错误!而配置错误的原因很可能是因为该文件由其他位置复制或移动过来所导致的!因此,你得要善用 restorecon 以及 chcon 来处理这方面的问题喔!
由於 SELinux 是整合到核心的一个核心功能,因此你几乎不需要启动什么额外的服务来开启 SELinux 的。启动完成后, SELinux 就启动了。不过,你刚刚也发现到当我们复制或移动某些数据到特定的目录时,可能由於没有注意到修改 SELinux 的安全性本文内容,结果导致网络服务无法顺利运行的问题!有没有什么方法可以记录当发生 SELinux 错误时,将那些有用的资讯记录下来,并且提供解决的方案呢?此时就得要底下的几个服务的辅助罗!
几乎所有 SELinux 相关的程序都会以 se 为开头,这个服务也是以 se 为开头!而 troubleshoot 大家都知道是错误克服,因此这个 setroubleshoot 自然就得要启动他啦!这个服务会将关於 SELinux 的错误信息与克服方法记录到 /var/log/messages 里头,所以你一定得要启动这个服务才好。那如何在启动的时候就启动 setroubleshoot 呢?这样处理先:
[root@www ~]# chkconfig --list setroubleshoot setroubleshoot 0:off 1:off 2:off 3:on 4:on 5:on 6:off # 我们的 Linux 运行模式是在 3 或 5 号,因此这两个要 on 即可。 [root@www ~]# chkconfig setroubleshoot on # 关於 chkconfig 我们会在后面章节介绍, --list 是列出目前的运行等级是否有启动, # 如果加上 on ,则是在启动时启动,若为 off 则启动时不启动。 |
这支服务默认几乎都会启动啦!除非你看到 3:off 或 5:off 时,才需要以『 chkconfig setroubleshoot on 』去配置一下。那么如果有发生错误时,信息像什么呢?我们刚刚不是以浏览器浏览 index.html 并导致错误吗?那就将该错误捉来瞧瞧!
[root@www ~]# cat /var/log/messages | grep setroubleshoot Mar 23 17:18:44 www setroubleshoot: SELinux is preventing the httpd from using potentially mislabeled files (/var/www/html/index.html). For complete SELinux messages. run sealert -l 6c028f77-ddb6-4515-91f4-4e3e719994d4 |
上面的错误信息可是同一行喔!大纲说的是『SElinux 被用来避免 httpd 读取到错误的安全性本文,想要查阅完整的数据,请运行 sealert -l 6c02...』没错!你注意到了!重点就是 sealert -l 啦!上面提供的资讯并不完整,想要更完整的说明得要靠 sealert 配合侦测到的错误代码来处理。实际处理后会像这样:
[root@www ~]# sealert -l 6c028f77-ddb6-4515-91f4-4e3e719994d4 Summary: SELinux is preventing the httpd from using potentially mislabeled files (/var/www/html/index.html). <==就是刚刚 /var/log/messages 的信息 Detailed Description: <==底下是更完整的描述!要看! SELinux has denied httpd access to potentially mislabeled file(s) (/var/www/html/index.html). This means that SELinux will not allow httpd to use these files. It is common for users to edit files in their home directory or tmp directories and then move (mv) them to system directories. The problem is that the files end up with the wrong file context which confined applications are not allowed to access. Allowing Access: <==若要允许存取,你需要进行的动作! If you want httpd to access this files, you need to relabel them using restorecon -v '/var/www/html/index.html'. You might want to relabel the entire directory using restorecon -R -v '/var/www/html'. ....(底下省略).... |
重点就是上面特殊字体显示的地方!你只要照著『Allowing Access』里面的提示去进行处理,就能够完成你的 SELinux 类型配置了!比对刚刚我们上个小节提到的restorecon与 chcon 你就能够知道, setroubleshoot 提供的信息有多有效了吧!
audit 是稽核的意思,这个 auditd 会将 SELinux 发生的错误资讯写入 /var/log/audit/audit.log 中!与上个服务相同的,你最好在启动时就配置这服务为启动的模式,因此可以照样造句:
[root@www ~]# chkconfig --list auditd auditd 0:off 1:off 2:on 3:on 4:on 5:on 6:off [root@www ~]# chkconfig auditd on # 若 3:off 及 5:off 时,才需要进行! |
与 setroubleshoot 不同的是, auditd 会将许多的 SELinux 资讯都记录下来,不只是错误信息而已,因此登录档 /var/log/audit/audit.log 非常的庞大!要直接到这文件里面去搜寻数据是挺累人的~还好,SELinux 有提供一个 audit2why 的命令来让我们查询错误信息的回报呢!那么这个命令如何使用呢?可以这样用的:
[root@www ~]# audit2why < /var/log/audit/audit.log # 意思是,将登录档的内容读进来分析,并输出分析的结果!结果有点像这样: type=AVC msg=audit(1237799959.349:355): avc: denied { getattr } for pid=24094 comm="httpd" path="/var/www/html/index.html" dev=hda2 ino=654685 scontext=root:s ystem_r:httpd_t:s0 tcontext=root:object_r:user_home_t:s0 tclass=file Was caused by: Missing or disabled TE allow rule. Allow rules may exist but be disabled by boolean settings; check boolean settings. You can see the necessary allow rules by running audit2allow with this audit message as input. |
audit2why 的用法与输出结果如上,比较有趣的是那个 AVC ,AVC 是 access vector cache 的缩写,目的是记录所有与 SELinux 有关的存取统计数据。输出的资讯当中,会有谈到产生错误的问题为何,如上表特殊字体部分,你会发现错误信息主要告知 type 不符,所以导致错误的发生啊!不过,就鸟哥来看,我个人觉得 setroubleshoot 比较好用呢!这两个好东西都可以帮助你解决 SELinux 的错误,因此,请务必至少要学会其中一项错误分析的方法喔!
现在你应该知道,一个主体程序能否读取到目标文件资源的重点在於 SELinux 的政策以及政策内的各项守则,然后再透过该守则的定义去处理各目标文件的安全性本文,尤其是『类型』的部分。现在我们也知道可以透过sestatus 与getenforce 去取得目前的 SELinux 状态。但是,能不能知道更详细的政策说明与守则项目呢?底下我们就来了解了解!
CentOS 5.x 默认使使用 targeted 政策,那么这个政策提供多少相关的守则呢?此时可以透过 seinfo 来查询喔!
[root@www ~]# seinfo [-Atrub] 选项与参数: -A :列出 SELinux 的状态、守则布林值、身份识别、角色、类别等所有资讯 -t :列出 SELinux 的所有类别 (type) 种类 -r :列出 SELinux 的所有角色 (role) 种类 -u :列出 SELinux 的所有身份识别 (user) 种类 -b :列出所有守则的种类 (布林值) 范例一:列出 SELinux 在此政策下的统计状态 [root@www ~]# seinfo Statistics for policy file: /etc/selinux/targeted/policy/policy.21 Policy Version & Type: v.21 (binary, MLS) <==列出政策所在档与版本 Classes: 61 Permissions: 220 Types: 1521 Attributes: 155 Users: 3 Roles: 6 Booleans: 213 Cond. Expr.: 190 Sensitivities: 1 Categories: 1024 Allow: 86561 Neverallow: 0 Auditallow: 34 Dontaudit: 5460 Role allow: 5 Role trans: 0 ....(底下省略).... # 从上面我们可以看到这个政策是 targeted ,此政策的安全性本文类别有 1521 个; # 而针对网络服务的守则 (Booleans) 共制订了 213 条守则! 范例二:列出与 httpd 有关的守则 (booleans) 有哪些? [root@www ~]# seinfo -b | grep httpd Rule loading disabled allow_httpd_mod_auth_pam allow_httpd_bugzilla_script_anon_write httpd_enable_ftp_server ....(底下省略).... # 你可以看到,有非常多的与 httpd 有关的守则订定呢! |
从上面我们可以看到与 httpd 有关的布林值,同样的,如果你想要找到有 httpd 字样的安全性本文类别时,就可以使用『 seinfo -t | grep httpd 』来查询了!如果查询到相关的类别或者是布林值后,想要知道详细的守则时,就得要使用 sesearch 这个命令了!
[root@www ~]# sesearch [-a] [-s 主体类别] [-t 目标类别] [-b 布林值] 选项与参数: -a :列出该类别或布林值的所有相关资讯 -t :后面还要接类别,例如 -t httpd_t -b :后面还要接布林值的守则,例如 -b httpd_enable_ftp_server 范例一:找出目标文件资源类别为 httpd_sys_content_t 的有关资讯 [root@www ~]# sesearch -a -t httpd_sys_content_t Found 74 av rules: allow readahead_t httpd_sys_content_t : file { ioctl read getattr lock }; allow readahead_t httpd_sys_content_t : dir { ioctl read getattr lock search }; ....(底下省略).... # 『 allow 主体程序安全性本文类别 目标文件安全性本文类别 』 # 如上,说明这个类别可以被那个主题程序的类别所读取,以及目标文件资源的格式。 范例二:找出主体程序为 httpd_t 且目标文件类别为 httpd 相关的所有资讯 [root@www ~]# sesearch -s httpd_t -t httpd_* -a Found 163 av rules: ....(中间省略).... allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock }; allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search }; allow httpd_t httpd_sys_content_t : lnk_file { ioctl read getattr lock }; ....(后面省略).... # 从上面的数据就可以看出当程序为 httpd_t 这个类别,是可以读取 # httpd_sys_content_t 的! |
你可以很轻易的查询到某个主体程序 (subject) 可以读取的目标文件资源 (Object) ,从我们上面的练习,我们也可以很轻松的就知道,为何 httpd_t 可以读取 httpd_sys_content_t 罗!那如果是布林值呢?里面又规范了什么?让我们来看看先:
范例三:我知道有个布林值为 httpd_enable_homedirs ,请问该布林值规范多少守则? [root@www ~]# sesearch -b httpd_enable_homedirs -a Found 21 av rules: allow httpd_t user_home_dir_t : dir { getattr search }; allow httpd_t cifs_t : file { ioctl read getattr lock }; allow httpd_t cifs_t : dir { ioctl read getattr lock search }; ....(后面省略).... |
从这个布林值的配置我们可以看到里面规范了非常多的主体程序与目标文件资源的放行与否!所以你知道了,实际规范这些守则的,就是布林值的项目啦!那也就是我们之前所说的一堆守则是也!你的主体程序能否对某些目标文件进行存取,与这个布林值非常有关系喔!因为布林值可以将守则配置为启动 (1) 或者是关闭 (0) 啦!
由 seinfo 与 sesearch 的输出资讯,我们也会得到实际的政策数据都是放置到 /etc/selinux/targeted/policy/ 底下,事实上,所有与 targetd 相关的资讯都是放置到 /etc/selinux/targeted 里面的呢!包括安全性本文相关的资讯。这部分等一下谈到安全性本文的默认值修改时,我们再来讨论。
上面我们透过 sesearch 知道了,其实 Subject 与 Object 能否有存取的权限,是与布林值有关的,那么系统有多少布林值可以透过 seinfo -b 来查询,但,每个布林值是启动的还是关闭的呢?这就来查询看看吧:
[root@www ~]# getsebool [-a] [布林值条款] 选项与参数: -a :列出目前系统上面的所有布林值条款配置为开启或关闭值 范例一:查询本系统内所有的布林值配置状况 [root@www ~]# getsebool -a NetworkManager_disable_trans --> off allow_console_login --> off allow_cvs_read_shadow --> off allow_daemons_dump_core --> on ....(底下省略).... # 您瞧!这就告诉你目前的布林值状态罗! |
那么如果查询到某个布林值,并且以 sesearch 知道该布林值的用途后,想要关闭或启动他,又该如何处置?
[root@www ~]# setsebool [-P] 布林值=[0|1] 选项与参数: -P :直接将配置值写入配置档,该配置数据未来会生效的! 范例一:查询 httpd_enable_homedirs 是否为关闭,若不为关闭,请关闭他! [root@www ~]# getsebool httpd_enable_homedirs httpd_enable_homedirs --> on <==结果是 on ,依题意给他关闭! [root@www ~]# setsebool -P httpd_enable_homedirs=0 [root@www ~]# getsebool httpd_enable_homedirs httpd_enable_homedirs --> off |
这个 setsebool 最好记得一定要加上 -P 的选项!因为这样才能将此配置写入配置档!这是非常棒的工具组!你一定要知道如何使用 getsebool 与 setsebool 才行!
还记得我们在使用 restorecon 时谈到每个目录或文件都会有默认的安全性本文吗?会制订目录的安全性本文,是因为系统的一些服务所放置文件的目录已经是确定的,当然有默认的安全性本文管理上较方便。那你如何查询这些目录的默认安全性本文呢?就得要使用 semanage 罗!
[root@www ~]# semanage {login|user|port|interface|fcontext|translation} -l [root@www ~]# semanage fcontext -{a|d|m} [-frst] file_spec 选项与参数: fcontext :主要用在安全性本文方面的用途, -l 为查询的意思; -a :添加的意思,你可以添加一些目录的默认安全性本文类型配置; -m :修改的意思; -d :删除的意思。 范例一:查询一下 /var/www/html 的默认安全性本文配置为何! [root@www ~]# semanage fcontext -l SELinux fcontext type Context ....(前面省略).... /var/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 ....(后面省略).... |
从上面的说明,我们知道其实 semanage 可以处理非常多的任务,不过,在这个小节我们主要想了解的是每个目录的默认安全性本文。如上面范例一所示,我们可以查询的到每个目录的安全性本文啦!而目录的配置可以使用正规表示法去指定一个范围。那么如果我们想要添加某些自订的目录的安全性本文呢?举例来说,我想要制订 /srv/samba 成为 public_content_t 的类型时,应该如何指定呢?
范例二:利用 semanage 配置 /srv/samba 目录的默认安全性本文为 public_content_t [root@www ~]# mkdir /srv/samba [root@www ~]# ll -Zd /srv/samba drwxr-xr-x root root root:object_r:var_t /srv/samba # 如上所示,默认的情况应该是 var_t 这个咚咚的! [root@www ~]# semanage fcontext -l | grep '/srv' /srv/.* all files system_u:object_r:var_t:s0 /srv/([^/]*/)?ftp(/.*)? all files system_u:object_r:public_content_t:s0 /srv/([^/]*/)?www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /srv/([^/]*/)?rsync(/.*)? all files system_u:object_r:public_content_t:s0 /srv/gallery2(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /srv directory system_u:object_r:var_t:s0 <==看这里! # 上面则是默认的 /srv 底下的安全性本文数据,不过,并没有指定到 /srv/samba 啦 [root@www ~]# semanage fcontext -a -t public_content_t "/srv/samba(/.*)?" [root@www ~]# semanage fcontext -l | grep '/srv/samba' /srv/samba(/.*)? all files system_u:object_r:public_content_t:s0 [root@www ~]# cat /etc/selinux/targeted/contexts/files/file_contexts.local # This file is auto-generated by libsemanage # Please use the semanage command to make changes /srv/samba(/.*)? system_u:object_r:public_content_t:s0 # 其实就是写入这个文件的罗! ^_^ [root@www ~]# restorecon -Rv /srv/samba* <==尝试恢复默认值 [root@www ~]# ll -Zd /srv/samba drwxr-xr-x root root system_u:object_r:public_content_t /srv/samba/ # 有默认值,以后用 restorecon 来修改比较简单! |
semanage 的功能很多,不过鸟哥主要用到的仅有 fcontext 这个项目的动作而已。如上所示,你可以使用 semanage 来查询所有的目录默认值,也能够使用他来添加默认值的配置!如果您学会这些基础的工具,那么 SELinux 对你来说,也不是什么太难的咚咚罗!
[root@www ~]# rpm -q vsftpd vsftpd-2.0.5-12.el5 <==出现这个才是对的!若没有出现,就是没安装 # 如果没有安装的话,你又已经有 IP 可以上网了,那么就这样安装: [root@www ~]# yum install vsftpd |
[root@www ~]# /etc/init.d/vsftpd start
|
[root@www ~]# pstree -p | grep vsftpd |-vsftpd(2377) <==找到了 PID 为 2377 喔! [root@www ~]# renice 10 2377 [root@www ~]# top -p grep 2377 <==重点是在观察! |
[root@www ~]# netstat -tlunp | grep vsftpd tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN 2377/vsftpd # 这样的答案够明显了吗? |
# 1. 先用 vbird 的身份登陆 vsftpd 看看: [root@www ~]# ftp localhost Connected to www.vbird.tsai. Name (localhost:root): vbird 331 Please specify the password. Password: <==这里输入 vbird 的口令喔! 500 OOPS: cannot change directory:/home/vbird Login failed. <==见鬼了!竟然无法登陆自己的家目录 /home/vbird 哩! ftp> bye [root@www ~]# ls -ld /home/vbird drwx------ 4 vbird vbird 4096 8月 18 18:22 /home/vbird # 权限明明是对的嘛!怎么会无法切换? # 2. 看看登录档有没有什么重要信息的说明: [root@www ~]# tail /var/log/messages Sep 11 16:57:31 www setroubleshoot: SELinux is preventing the ftp daemon from reading users home directories (/). For complete SELinux messages. run sealert -l b8bdaf2d-b083-4e28-9465-91fae8df63b1 # 3. 照著作一下: [root@www ~]# sealert -l b8bdaf2d-b083-4e28-9465-91fae8df63b1 Summary: SELinux is preventing the ftp daemon from reading users home directories (/). ....(中间省略).... The following command will allow this access: setsebool -P ftp_home_dir=1 ....(底下省略).... |
[root@www ~]# setsebool -P ftp_home_dir=1 [root@www ~]# ftp localhost Connected to www.vbird.tsai. Name (localhost:root): vbird 331 Please specify the password. Password: 230 Login successful. <==看吧!顺利登陆罗! Remote system type is UNIX. Using binary mode to transfer files. ftp> bye |
2009/09/11:加入了 nohup 的说明罗!并加入了情境模拟题
出处:http://vbird.dic.ksu.edu.tw/linux_basic/0440processcontrol.php