Linux中grep命令的12个实践例子

你是否遇到过需要在文件中查找一个特定的字符串或者样式,但是不知道从哪儿开始?那么,就请grep来帮你吧。

未分类

grep是每个Linux发行版都预装的一个强有力的文件模式搜索工具。无论何种原因,如果你的系统没有预装它的话,你可以很容易的通过系统的包管理器来安装它(Debian/Ubuntu系中的apt-get和RHEl/CentOS/Fedora系中的yum)。

$ sudo apt-get install grep #Debian/Ubuntu $ sudo yum install grep #RHEL/CentOS/Fedora 

我发现使用现实世界中的真实例子让你投身其中是让你接触grep命令的最容易方式。

1. 搜索和寻找文件

假设你已经在你的电脑上安装了一个全新的Ubuntu,然后你打算卸载Python。你浏览网页寻找教程,但是你发现存在两个不同版本的Python在使用,而你不知道你的Ubuntu安装器到底在你的系统中安装了哪个版本的Python,也不知道它安装了哪些模块。解决这个烦恼只需简单的运行以下命令:

$ sudo dpkg -l | grep -i python 

输出例子

ii  python2.7         2.7.3-0ubuntu3.4 Interactive high-level object-oriented language (version 2.7)
   ii  python2.7-minimal 2.7.3-0ubuntu3.4 Minimal subset of the Python language (version 2.7)
   ii  python-openssl    0.12-1ubuntu2.1  Python wrapper around the OpenSSL library
   ii  python-pam        0.4.2-12.2ubuntu4 A Python interface to the PAM library

首先,我们运行dpkg -l列出你系统上安装的.deb包。接着,我们使用管道将输出结果传输给命令grep -i python,这一步可以简单解释为把结果传输给grep然后过滤出所有含有python的项,并返回结果。–i选项用于忽略大小写,因为 grep 是大小写敏感的。使用选项-i是个好习惯,除非你打算进行更细节的搜索。

2. 搜索和过滤文件

grep还可以在一个或多个文件里用于搜索和过滤。让我们来看一个这样的情景:

你的Apache网页服务器出现了问题,你不得不从许多专业网站里找一个发帖询问。好心回复你的人让你粘贴上来你的/etc/apache2/sites-available/default-ssl文件内容。假如你能移除掉所有的注释行,那么对你,对帮你的人,以及所有阅读该文件的人,不是更容易发现问题吗?你当然可以很容易的做到!只需这样做就可以了:

$ sudo grep -v "#" /etc/apache2/sites-available/default-ssl 

选项-v是告诉grep命令反转它的输出结果,意思就是不输出匹配的项,做相反的事,打印出所有不匹配的项。这个例子中,有#的是注释行(译注:其实这个命令并不准确,包含“#”的行不全是注释行。关于如何精确匹配注释行,可以了解更多的关于正则表达式的内容。)。

3. 找出所有的mp3文件

grep命令对于过滤来自于标准输出的结果非常有用。例如,假设你的一个文件夹里面全是各种格式的音乐文件。你要找出艺术家jayZ的所有mp3格式的音乐文件,里面也不要有任何混合音轨。使用find命令再结合管道使用grep就可以完成这个魔法:

$ sudo find . -name ".mp3" | grep -i JayZ | grep -vi "remix"" 

在这个例子中,我们使用find命令打印出所有以.mp3为后缀名的文件,接着将其使用管道传递给grep -i过滤和打印出名字为“JayZ”的文件,再使用管道传送给grep -vi以便过滤掉含有“remix”的项。

35个Linux中find命令的实践例子: http://www.tecmint.com/35-practical-examples-of-linux-find-command/

4. 在搜索字符串前面或者后面显示行号

另外两个选项是-A和-B之间的切换,是用以显示匹配的行以及行号,分别控制在字符串前或字符串后显示的行数。Man页给出了更加详细的解释,我发现一个记忆的小窍门:-A=after、-B=before。

$ sudo ifconfig | grep -A 4 etho $ sudo ifconfig | grep -B 2 UP

5. 在匹配字符串周围打印出行号

grep命令的-C选项和例4中的很相似,不过打印的并不是在匹配字符串的前面或后面的行,而是打印出两个方向都匹配的行(译注:同上面的记忆窍门一样:-C=center,以此为中心): $ sudo ifconfig | grep -C 2 lo

6. 计算匹配项的数目

这个功能类似于将grep输出的结果用管道传送给计数器(wc程序),grep内建的选项可以达到同样的目的:

$ sudo ifconfig | grep -c inet6 

7. 按给定字符串搜索文件中匹配的行号

当你在编译出错时需要调试时,grep命令的-n选项是个非常有用的功能。它能告诉你所搜索的内容在文件的哪一行:

$ sudo grep -n "main" setup.py 

8. 在所有目录里递归的搜索

假若你要在当前文件夹里搜索一个字符串,而当前文件夹里又有很多子目录,你可以指定一个-r选项以便于递归的搜索: $ sudo grep -r “function” *

9. 进行精确匹配搜索

传递-w选项给grep命令可以在字符串中进行精确匹配搜索(译注:包含要搜索的单词,而不是通配)。例如,像下面这样输入:

$ sudo ifconfig | grep -w “RUNNING” 

将打印出含有引号内匹配项的行。另外,你还可以试一下这个:

$ sudo ifconfig | grep -w “RUN” 

搜索这个匹配项时,若搜索的东西里面没有这样的一个单独的单词,将什么也不会返回。

10. 在Gzip压缩文件中搜索

我们还要关注一下grep的衍生应用。第一个是zgrep,这个与zcat很相似,可以用于gzip压缩过的文件。它有与grep相似的命令选项,使用方式也一样:

$ sudo zgrep -i error /var/log/syslog.2.gz 

11. 在文件中匹配正则表达式

egrep是另一个衍生应用,代表着“扩展全局正则表达式”。它可以识别更多的正则表达式元字符,例如at + ? | 和()。在搜索源代码文件时,egrep是一个非常有用的工具,还有其他的一些零碎代码文件的搜索需要,使得这样的搜索能力成为必需。可以在grep命令中使用选项-E来启用它。

$ sudo grep -E

12. 搜索一个固定匹配字符串

fgrep用于在一个文件或文件列表中搜索固定样式的字符串。功能与grep -F同。fgrep的一个通常用法为传递一个含有样式的文件给它:

$ sudo fgrep -f file_full_of_patterns.txt file_to_search.txt 

这仅仅是grep命令的开始,你可能已经注意到,它对于实现各种各样的需求简直是太有用了。除了这种我们运行的这种只有一行的命令,grep还可以写成cron任务或者自动的shell脚本去执行。保持好奇心,试验一下man页的各个选项,为实现你的目的写出一些grep表达式吧。

Linux 查看空间使用情况

在日常的Linux巡检中,我们会遇到文件系统目录使用空间很高的情况,例如如下利用”df -h “查看到根目录空间使用超过80%。而我们仅仅知道是根目录空间使用过高,这样是不够的。还需要知道是目录还是文件让根目录空间使用过高。通常我们使用的命令是”du -sh *”。

第一步:查看Linux系统的文件系统使用情况,如下可以看到根目录”/”已经使用81%。

[root@hostname ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda6              67G   51G   13G  81% /
tmpfs                  16G  152K   16G   1% /dev/shm
/dev/sda3              99G  188M   94G   1% /arch
/dev/sda1             197G  188M  187G   1% /u01
/dev/sda2             197G   50G  138G  27% /u02

第二步:进入根目录,利用du -sh 命令查询各个目录或者文件占用空间的情况,因为/u02是独立的文件系统,所以可以忽略。我们关注的是root这个目录,占用了空间47G。

[root@hostname ~]# cd /

[root@hostname /]# du -sh *
20K     arch
7.6M    bin
27M     boot
324K    dev
36M     etc
36K     home
136M    lib
26M     lib64
16K     lost+found
4.0K    media
0       misc
4.0K    mnt
0       net
8.0K    opt
4.0K    orbit-root
--省略/proc目录统计的报错
0       proc
47G     root    ##根目录文件系统使用最大的目录
15M     sbin
0       selinux
4.0K    srv
0       sys
80K     tmp
20K     u01
49G     u02

第三步:进入root目录,其实也是root用户的主目录。我们从ls命令可以猜到可能是【apache-tomcat-6.0.36-linux】这个tomcat的程序目录占用比较多。

[root@hostname /]# cd root
[root@hostname ~]# ls
anaconda-ks.cfg  apache-tomcat-6.0.36-linux  Desktop  Documents  Downloads  install.log  install.log.syslog  Music  Pictures  Public  Templates  Videos

第四步:通过统计发现,确实是【apache-tomcat-6.0.36-linux】这个目录占用了47G。但是到此问题还没有结束,因为既然是应用程序的目录,根据我的经验很可能是tomcat的日志文件占用空间比较多。

[root@hostname ~]# du -sh *
4.0K    anaconda-ks.cfg
47G     apache-tomcat-6.0.36-linux
4.0K    Desktop
4.0K    Documents
4.0K    Downloads
56K     install.log
12K     install.log.syslog
4.0K    Music
4.0K    Pictures
4.0K    Public
4.0K    Templates
4.0K    Videos

第五步:既然看到有tomcat的目录,很可能这个tomcat运行着,利用ps命令查看是否有tomcat的进程,一般可以过滤java这个关键词。如下,果然有tomcat在运行着。那么很可能占用空间最多就是tomcat的日志文件。

[root@hostname ~]# ps -ef|grep java
root      4879  4836  0 08:26 pts/0    00:00:00 grep java
root     11864     1 47 Aug16 ?        26-03:11:29 /usr/bin/java -Djava.util.logging.config.file=/root/apache-tomcat-6.0.36-linux/conf/logging.properties -Xms512m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256m -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/root/apache-tomcat-6.0.36-linux/endorsed -classpath /root/apache-tomcat-6.0.36-linux/bin/bootstrap.jar -Dcatalina.base=/root/apache-tomcat-6.0.36-linux -Dcatalina.home=/root/apache-tomcat-6.0.36-linux -Djava.io.tmpdir=/root/apache-tomcat-6.0.36-linux/temp org.apache.catalina.startup.Bootstrap start

第六步:进入tomcat的程序目录,查看哪个目录占用的空间最大。如下,发现是一个【fare】的目录占用了46G,而【logs】是日志目录却占用了23M。

[root@hostname ~]# cd apache-tomcat-6.0.36-linux
[root@hostname apache-tomcat-6.0.36-linux]# ls
backup  bin  conf  fare  lib  LICENSE  logs  NOTICE  RELEASE-NOTES  RUNNING.txt  temp  webapps  work
[root@hostname apache-tomcat-6.0.36-linux]# du -sh *
92K     backup
882M    bin
108K    conf
46G     fare
6.8M    lib
40K     LICENSE
23M     logs
4.0K    NOTICE
12K     RELEASE-NOTES
16K     RUNNING.txt
7.9M    temp
188M    webapps
7.1M    work

第七步:继续一探究竟【fare】目录里面到底存放的是什么类型的目录或者文件。如下看到有很多类似日志文件,如common.log和pricing.log。通过和开发人员沟通之后,确定确实日志文件。

[root@hostname apache-tomcat-6.0.36-linux]# cd fare
[root@hostname fare]# ls
common.log             common.log.2017-09-21  common.log.2017-10-03     pricing.log.2017-09-10  pricing.log.2017-09-22  pricing.log.2017-10-04
common.log.2017-09-10  common.log.2017-09-22  common.log.2017-10-04     pricing.log.2017-09-11  pricing.log.2017-09-23  pricing.log.2017-10-05
common.log.2017-09-11  common.log.2017-09-23  common.log.2017-10-05     pricing.log.2017-09-12  pricing.log.2017-09-24  pricing.log.2017-10-06
common.log.2017-09-12  common.log.2017-09-24  common.log.2017-10-06     pricing.log.2017-09-13  pricing.log.2017-09-25  pricing.log.2017-10-07
common.log.2017-09-13  common.log.2017-09-25  common.log.2017-10-07     pricing.log.2017-09-14  pricing.log.2017-09-26  pricing.log.2017-10-08
common.log.2017-09-14  common.log.2017-09-26  common.log.2017-10-08     pricing.log.2017-09-15  pricing.log.2017-09-27  pricing.log.2017-10-09
common.log.2017-09-15  common.log.2017-09-27  common.log.2017-10-09     pricing.log.2017-09-16  pricing.log.2017-09-28  spring.log
common.log.2017-09-16  common.log.2017-09-28  common.zip                pricing.log.2017-09-17  pricing.log.2017-09-29  struts2.log
common.log.2017-09-17  common.log.2017-09-29  framework.log             pricing.log.2017-09-18  pricing.log.2017-09-30  xwork2.log
common.log.2017-09-18  common.log.2017-09-30  hibernate.log             pricing.log.2017-09-19  pricing.log.2017-10-01
common.log.2017-09-19  common.log.2017-10-01  hibernate.log.2017-01-03  pricing.log.2017-09-20  pricing.log.2017-10-02
common.log.2017-09-20  common.log.2017-10-02  pricing.log               pricing.log.2017-09-21  pricing.log.2017-10-03

第八步:继续查看哪个目录或者文件占用的空间最大,发现都是common.log和pricing.log相关的文件占用的空间最大,都是700M以上。至此,已经查明占用根目录”/”空间最多的原因是tomcat的日志文件太多,而且每一个日志文件都很大。

[root@hostname fare]# du -sh *|sort -h
0       framework.log
0       hibernate.log.2017-01-03
0       spring.log
0       struts2.log
0       xwork2.log
4.0K    hibernate.log
17M     common.zip
215M    pricing.log
216M    common.log
667M    pricing.log.2017-10-08
668M    common.log.2017-10-08
674M    common.log.2017-10-05
674M    pricing.log.2017-10-05
678M    common.log.2017-10-07
678M    pricing.log.2017-10-07
679M    common.log.2017-10-06
679M    pricing.log.2017-10-06
683M    common.log.2017-10-04
683M    pricing.log.2017-10-04
690M    pricing.log.2017-09-10
691M    common.log.2017-09-10
711M    common.log.2017-09-12
711M    pricing.log.2017-09-12
719M    pricing.log.2017-09-11
720M    common.log.2017-09-11
737M    common.log.2017-09-30
737M    pricing.log.2017-09-28
737M    pricing.log.2017-09-30
738M    common.log.2017-09-28
742M    common.log.2017-09-29
742M    pricing.log.2017-09-29
744M    pricing.log.2017-10-09
745M    common.log.2017-10-09
751M    common.log.2017-10-01
751M    pricing.log.2017-10-01
754M    common.log.2017-09-13
754M    pricing.log.2017-09-13
760M    common.log.2017-10-03
760M    pricing.log.2017-10-03
783M    pricing.log.2017-10-02
784M    common.log.2017-10-02
791M    pricing.log.2017-09-18
792M    common.log.2017-09-18
797M    common.log.2017-09-27
797M    pricing.log.2017-09-27
804M    common.log.2017-09-17
804M    common.log.2017-09-19
804M    pricing.log.2017-09-17
804M    pricing.log.2017-09-19
808M    common.log.2017-09-26
808M    pricing.log.2017-09-26
815M    pricing.log.2017-09-24
816M    common.log.2017-09-24
821M    common.log.2017-09-14
821M    pricing.log.2017-09-14
821M    pricing.log.2017-09-23
822M    common.log.2017-09-23
826M    common.log.2017-09-25
826M    pricing.log.2017-09-25
827M    common.log.2017-09-16
827M    pricing.log.2017-09-15
827M    pricing.log.2017-09-16
828M    common.log.2017-09-15
831M    common.log.2017-09-22
831M    pricing.log.2017-09-22
851M    common.log.2017-09-21
851M    pricing.log.2017-09-21
860M    common.log.2017-09-20
860M    pricing.log.2017-09-20

第九步:从文件的命令规律,可以看出日志文件日期保留一个月,检查root用户是否有定时删除日志文件计划。如下命令查看所示,确实有每天凌晨03:15进行日志文件删除的计划。但是由于日志文件太多和根目录空间大小原因,导致根目录空间使用比例过高。在有部署自动监控工具,如zabbix等,会自动发送告警。

[root@hostname ~]# crontab -l
15 3 * * * /u02/shell/rm_log_pricing.sh
[root@hostname ~]# cat /u02/shell/rm_log_pricing.sh
find /root/apache-tomcat-6.0.36-linux/bin/fare/  -name "common.log.2*" -mtime +30 | xargs rm -f
find /root/apache-tomcat-6.0.36-linux/bin/fare/  -name "pricing.log.2*" -mtime +30 | xargs rm -f

总结:

从运维的角度,不建议tomcat等应用程序部署在和Linux操作系统相关的文件系统中,尤其是直接部署在根目录下。一般都建议使用独立的文件系统来部署应用程序,无论从IO性能监控,文件系统空间使用监控都是有利的。

Linux Loader 机制与内核模块修复

0x0 前言

在吃着月饼喝着茶的闲暇时间里,突然接到某单位的应急通知。赶往现场进行初步勘察后,发现攻击者手段非常暴力,直接删除系统相关关键模块(包括 PAM 模块、基础内核驱动模块等),导致后续用户无法登录操作系统。

在尝试恢复 PAM 模块后,正常登录系统,但由于缺少基础的核心模块,网络、USB 挂载等仍无法正常使用。在下载部分二进制驱动包进行安装后,重启开始出现问题(截图为后期复现):

未分类

确认 /lib/modules/ 下确实存在此文件,但重启依然出现此问题。

而由于对 Linux Loader 机制的不熟悉,现场并未能解决此问题(菜。同时在不确定攻击者是否也删除了正常业务程序组件的情况下,恢复的成本较大,于是备份关键数据,提取相关样本与日志后,对系统进行重装,恢复正常业务。

0x1 Linux 启动与内核加载

1.1 bootloader

首先,还是从我们的老朋友 BIOS 进行加电自检(POST,Power-On Self-Test)后,开始读取 MBR 记录。MBR 为 512 字节大小的扇区,其中前 446 字节硬编码着 bootloader 程序。BIOS 从 MBR 记录读取 bootloader 程序,将其加载到内存,并运行该程序。

对于不同的操作系统,有不同的 bootloader 程序,一般在安装操作系统时,安装程序会向 MBR 写入 bootloader 程序。如 Windows 操作系统,使用自带的 bootloader 程序。对于 Linux 发行版,一般使用新版的 GRUB2 来生成并写入 bootloader。

bootloader 的工作便是载入内核文件,使操作系统正常运行。

1.2 内核文件

在 Linux 中,由 bootloader 载入的内核文件位于 /boot 节点下:

[root@centos boot]# ls --format=single-column /boot
config-2.6.32-696.el6.x86_64 # 内核编译时启用的配置信息与模块设定
efi # EFI 引导程序
grub # GRUB 引导程序支持
initramfs-2.6.32-696.el6.x86_64.img # 虚拟文件系统,主角 ;-)
symvers-2.6.32-696.el6.x86_64.gz # 驱动模块符号表
System.map-2.6.32-696.el6.x86_64 # 内核符号表
vmlinuz-2.6.32-696.el6.x86_64 # 内核文件

如上,vmlinuz 便是 bootloader 载入的 Linux 内核文件,内核文件主要负责检测基础的硬件设施,并载入相关驱动,这些驱动一般位于 /lib/modules/<内核版本>/ 目录下。

那么 initramfs 是干嘛的?当内核启动时,需要往 /lib/modudles 下读取驱动文件,以支持 SATA、USB 等接口的设备,但是明显 /lib/modules 是存储于 SATA 磁盘中,没有 SATA 驱动的情况下也无法读取挂载,这里就出现了先有鸡还是先有蛋的问题。

而 initramfs 便是来解决这个问题,initramfs 事实上是一个具有根目录结构的文件,其中包含基础的应用程序,以及核心的内核模块,例如 SCSI、SATA、USB 等,用于支持最基础的外部设备。

1.3 解剖 initramfs

新建目录,将 initramfs 拷贝到目标目录下:

[root@centos ~]# mkdir /tmp/initramfs
[root@centos ~]# cp /boot/initramfs-2.6.32-696.el6.x86_64.img /tmp/initramfs/initramfs.img

initramfs 使用 gzip 进行压缩,将其解压:

[root@centos ~]# cd /tmp/initramfs/
[root@centos initramfs]# file initramfs.img 
initramfs.img: gzip compressed data, from Unix, last modified: Wed Oct  4 17:17:17 2017, max compression
[root@centos initramfs]# mv initramfs.img initramfs.gz
[root@centos initramfs]# gzip -d initramfs.gz 

在解压完成后,实际上文件使用 cpio 进行归档,最后我们使用 cpio 将其解压出来:

[root@centos initramfs]# file initramfs
initramfs: ASCII cpio archive (SVR4 with no CRC)

# -i 解压文件
# -d 必要时创建目录
# -H newc 指定类型为 SVR4 的归档文件
# --no-absolute-filenames 不要将文件解压覆盖到绝对路径
[root@centos initramfs]# cpio -i -d -H newc --no-absolute-filenames < initramfs
108638 blocks

从最后的目录结构可以看到 initramfs 的真实内容:

[root@centos initramfs]# ll
total 54432
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 bin
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 cmdline
drwxr-xr-x. 3 root root     4096 Oct  5 22:50 dev
-rw-r--r--. 1 root root       23 Oct  5 22:50 dracut-004-409.el6_8.2
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 emergency
drwxr-xr-x. 7 root root     4096 Oct  5 22:50 etc
-rwxr-xr-x. 1 root root     8989 Oct  5 22:50 init
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-finished
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-settled
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-timeout
drwxr-xr-x. 7 root root     4096 Oct  5 22:50 lib
drwxr-xr-x. 3 root root     4096 Oct  5 22:50 lib64
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 mount
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 netroot
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-mount
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-pivot
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-trigger
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-udev
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 proc
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sbin
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sys
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sysroot
drwxrwxrwt. 2 root root     4096 Oct  5 22:50 tmp
drwxr-xr-x. 7 root root     4096 Oct  5 22:50 usr
drwxr-xr-x. 4 root root     4096 Oct  5 22:50 var

列一下 lib/modules/<内核版本>/kernel/drivers 下的驱动文件:

[root@centos initramfs]# ls lib/modules/2.6.32-696.el6.x86_64/kernel/drivers/
acpi
ata
atm
auxdisplay
bcma
block
bluetooth
cdrom
<...snippets...>

initramfs 中包含最核心的驱动程序,bootloader 在启动时,将 initramfs 临时挂载到根目录,在内核文件正常加载驱动后,对其进行卸载,并挂载真正的根目录节点。

最后,内核程序启动 init / systemd 对系统服务进行加载。

1.4 bootloader 配置

在 Linux 发行版下,bootloader 通常由 GRUB 程序进行管理,而 bootloader 又负责加载内核文件,较新的发行版一般使用新的 GRUB2 进行引导。

由于笔者使用的是 CentOS 6.X,所以此时默认还是旧版的 GRUB 引导管理程序,但不同版本配置上大同小异,所以以旧版为例。

默认情况下,/boot/grub 下(新版为/boot/grub2)存放 GRUB 的配置文件:

[root@centos ~]# ls /boot/grub
grub.conf # GRUB 的引导菜单配置文件
stage1
stage2
<...snippets...>

可以注意到目录下有 stage1 和 stage2 文件,这个其实便是 bootloader 程序。由于 MBR 区域只有可怜的 512 字节,而 bootloader 程序相对都会比较大,所以 GRUB 将启动分为两个阶段,真正存在于 MBR 处的代码便是 stage1 程序,再由此加载真正的 bootloader 程序 stage2。

再看看主配置文件 /boot/grub/grub.conf 的内容:

# grub.conf generated by anaconda

default=0
timeout=5

title CentOS 6 (2.6.32-696.el6.x86_64)
    root (hd0,0)
    kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=/dev/mapper/vg_centos-lv_root nomodeset rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos/lv_swap rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_centos/lv_root  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
    initrd /initramfs-2.6.32-696.el6.x86_64.img

通过配置项名称应该都可以猜到相关的功能,例如 default 设置默认的启动菜单为 Centos 6 项,默认超时为 5 秒钟。

在 title 中,则定义了菜单项:

root (hd0,0)
kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=/dev/mapper/vg_centos-lv_root nomodeset rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos/lv_swap rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_centos/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32-696.el6.x86_64.img

root 指定 /boot 节点的位置,如果是多个磁盘,则从 hd0、hd1 等依次排列。后面的 0 代表所在的分区位置。

GRUB 从 0 开始索引分区,新版 GRUB2 则从 1 开始索引分区,磁盘索引一致,都是从 0 开始。

kernel 指令负责载入内核文件,包括载入的根目录位置、语言、键盘等参数。

initrd 负责挂载 initramfs 虚拟文件系统。

0x2 内核模块依赖重建

2.1 内核模块

Linux 中的内核模块通常与内核进行分离,作为独立的模块进行加载,当然也可以将其编译到内核中。独立的内核模块存放于 /lib/modules/<内核版本> 下。

该目录下的文件 modules.dep,记录了内核模块位置、依赖等信息。对于现在各种各样的设备驱动,手工配置依赖信息非常繁琐,所以当加入驱动后,可以通过 depmod 自动生成依赖信息:

depmod -a
依赖信息会被写入到 modules.dep 文件中,内核通过该文件对驱动进行正确加载。

2.2 问题重现

从引导过程中可以发现,vmlinuz 内核主要依赖 /lib/modules 下的内核驱动来对外部设备提供支持。

而在这起事件中,攻击者恶意删除了/lib/modules 下的所有文件。

于是在后续安装驱动中,/lib/modules 的内容被同步到 initramfs 中,但此时目录下已然没有完整的驱动信息。所以内核在挂载 initramfs 后,无法正常加载驱动程序,提示无法找到 modules.dep 文件,此时并非读取真正根目录下的 /lib/modules :-)。

2.3 修复内核模块

对于 /lib/modules 下的内核模块,正常通过编译 Linux 内核来生成,当然也可以用过 yum / apt 等在线包管理工具来重新安装 Linux 内核。

在机器与网络隔离的情况下,无法通过网络下载编译完的二进制文件,也许只能通过自行编译内核来修复。

但编译内核也需要对应的编译工具、环境、源码包等。另一种更简单的方式,可以下载对应的发行版的镜像,来进行修复。

首先通过镜像引导,进入 rescue 救援模式终端,由于发行版的版本、内核型号都相同,同时镜像也是跑在相同的机器上,所以载入的驱动也是一致。

通常进入救援模式时,都会自动帮你挂载原机的系统分区,例如 CentOS 将其挂在到 /mnt/sysimage 下。

1)先将所有驱动模块拷贝到原本的系统节点:

cp -R /lib/modules/2.6.32-696.el6.x86_64 /mnt/sysimage/lib/modules/

2)切换 /mnt/sysimage 为根目录:

chroot /mnt/sysimage

此时访问 / 下的任何内容,实际上为 /mnt/sysimage 。

3)进入 /boot 节点,重构 initramfs 镜像,记得备份:

cd /boot
cp initramfs-2.6.32-696.el6.x86_64.img initramfs-2.6.32-696.el6.x86_64.org

# -f 覆盖原始 initramfs 镜像
# -v 显示详细信息
dracut -f -v initramfs-2.6.32-696.el6.x86_64.img 2.6.32-696.el6.x86_64

dracut 用于重构 initramfs 镜像,最后的内核版本号要对应 /lib/modules 下的版本。

4)如果过程中修改了其他文件(例如修改了 shadow 等文件),由于 SELinux 的缘故,需要加入 SELinux 重建标识:

touch /.autorelabel

重启,首次进入时,等待 SELinux 重新建立策略:

未分类

再次重启后,正常进入系统,基本模块修复:

未分类

0x4 总结

  • 内核通过 initramfs 载入核心驱动为基础的外部设备提供支持
  • 内核模块位于 /lib/modules/<内核版本> 下,modules.dep 记录模块索引,使用 depmod -a 可以自动建立依赖信息
  • 使用 dracut 可以对 initramfs 进行重建,将 /lib/modules/ 下的核心模块打包到虚拟文件系统当中
  • 在 SELinux 的上下文下,需要建立 /.autorelabel 通知 SELinux 重新建立策略

总体而言都是在干运维的活,但是 Loader 的加载机制还是十分有趣。

Supervisor安装与配置(Linux/Unix进程管理工具)

Supervisor(http://supervisord.org/)是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。

因为Supervisor是Python开发的,安装前先检查一下系统否安装了Python2.4以上版本。下面以CentOS7,Python2.7版本环境下,介绍Supervisor的安装与配置步聚:

一、安装Python包管理工具(easy_install)

easy_install是setuptools包里带的一个命令,使用easy_install实际上是在调用setuptools来完成安装模块的工作,所以安装setuptools即可。

wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py -O - | sudo python

二、安装supervisor

easy_install supervisor

supervisor安装完成后会生成三个执行程序:supervisortd、supervisorctl、echo_supervisord_conf,分别是supervisor的守护进程服务(用于接收进程管理命令)、客户端(用于和守护进程通信,发送管理进程的指令)、生成初始配置文件程序。

三、配置

运行supervisord服务的时候,需要指定supervisor配置文件,如果没有显示指定,默认在以下目录查找:

$CWD/supervisord.conf
$CWD/etc/supervisord.conf
/etc/supervisord.conf
/etc/supervisor/supervisord.conf (since Supervisor 3.3.0)
../etc/supervisord.conf (Relative to the executable)
../supervisord.conf (Relative to the executable)

$CWD表示运行supervisord程序的目录。

可以通过运行echo_supervisord_conf程序生成supervisor的初始化配置文件,如下所示:

mkdir /etc/supervisor
echo_supervisord_conf > /etc/supervisor/supervisord.conf

四、配置文件参数说明

supervisor的配置参数较多,下面介绍一下常用的参数配置,详细的配置及说明,请参考官方文档介绍。

注:分号(;)开头的配置表示注释

[unix_http_server]
file=/tmp/supervisor.sock   ;UNIX socket 文件,supervisorctl 会使用
;chmod=0700                 ;socket文件的mode,默认是0700
;chown=nobody:nogroup       ;socket文件的owner,格式:uid:gid

;[inet_http_server]         ;HTTP服务器,提供web管理界面
;port=127.0.0.1:9001        ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
;username=user              ;登录管理后台的用户名
;password=123               ;登录管理后台的密码

[supervisord]
logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB        ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
logfile_backups=10           ;日志文件保留备份数量默认10,设为0表示不备份
loglevel=info                ;日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ;pid 文件
nodaemon=false               ;是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024                  ;可以打开的文件描述符的最小值,默认 1024
minprocs=200                 ;可以打开的进程数的最小值,默认 200

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致
;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord

; [program:xx]是被管理的进程配置参数,xx是进程的名称
[program:xx]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run  ; 程序启动命令
autostart=true       ; 在supervisord启动的时候也自动启动
startsecs=10         ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
autorestart=true     ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
startretries=3       ; 启动失败自动重试次数,默认是3
user=tomcat          ; 用哪个用户启动进程,默认是root
priority=999         ; 进程启动优先级,默认999,值小的优先启动
redirect_stderr=true ; 把stderr重定向到stdout,默认false
stdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默认50MB
stdout_logfile_backups = 20   ; stdout 日志文件备份数,默认是10
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
stopasgroup=false     ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=false     ;默认为false,向进程组发送kill信号,包括子进程

;包含其它配置文件
[include]
files = relative/directory/*.ini    ;可以指定一个或多个以.ini结束的配置文件

include示例:

[include]
files = /opt/absolute/filename.ini /opt/absolute/*.ini foo.conf config??.ini

五、配置管理进程

进程管理配置参数,不建议全都写在supervisord.conf文件中,应该每个进程写一个配置文件放在include指定的目录下包含进supervisord.conf文件中。

1> 创建/etc/supervisor/config.d目录,用于存放进程管理的配置文件
2> 修改/etc/supervisor/supervisord.conf中的include参数,将/etc/supervisor/conf.d目录添加到include中

[include]
files = /etc/supervisor/config.d/*.ini

未分类

supervisor配置文件目录结构

下面是配置Tomcat进程的一个例子:

[program:tomcat]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
autostart=true
autorestart=true
startsecs=5
priority=1
stopasgroup=true
killasgroup=true

六、启动Supervisor服务

supervisord -c /etc/supervisor/supervisord.conf

七、控制进程

7.1 交互终端

supervisord启动成功后,可以通过supervisorctl客户端控制进程,启动、停止、重启。运行supervisorctl命令,不加参数,会进入supervisor客户端的交互终端,并会列出当前所管理的所有进程。

未分类

上图中的tomcat就是我们在配置文件中[program:tomcat]指定的名字。
输入help可以查看可以执行的命令列表,如果想看某个命令的作用,运行help 命令名称,如:help stop

stop tomcat  // 表示停止tomcat进程
stop all     // 表示停止所有进程
// ...

7.2 bash终端

supervisorctl status
supervisorctl stop tomcat
supervisorctl start tomcat
supervisorctl restart tomcat
supervisorctl reread
supervisorctl update

7.3 Web管理界面

未分类

出于安全考虑,默认配置是没有开启web管理界面,需要修改supervisord.conf配置文件打开http访权限,将下面的配置:

;[inet_http_server]         ; inet (TCP) server disabled by default
;port=127.0.0.1:9001        ; (ip_address:port specifier, *:port for all iface)
;username=user              ; (default is no username (open server))
;password=123               ; (default is no password (open server))

修改成:

[inet_http_server]         ; inet (TCP) server disabled by default
port=0.0.0.0:9001          ; (ip_address:port specifier, *:port for all iface)
username=user              ; (default is no username (open server))
password=123               ; (default is no password (open server))
  • port:绑定访问IP和端口,这里是绑定的是本地IP和9001端口
  • username:登录管理后台的用户名
  • password:登录管理后台的密码

八、开机启动Supervisor服务

8.1 配置systemctl服务

1> 进入/lib/systemd/system目录,并创建supervisor.service文件

[Unit]
Description=supervisor
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown
ExecReload=/usr/bin/supervisorctl $OPTIONS reload
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

2> 设置开机启动

systemctl enable supervisor.service
systemctl daemon-reload

3> 修改文件权限为766

chmod 766 supervisor.service

8.2 配置service类型服务

#!/bin/bash
#
# supervisord   This scripts turns supervisord on
#
# Author:       Mike McGrath <[email protected]> (based off yumupdatesd)
#
# chkconfig:    - 95 04
#
# description:  supervisor is a process control utility.  It has a web based
#               xmlrpc interface as well as a few other nifty features.
# processname:  supervisord
# config: /etc/supervisor/supervisord.conf
# pidfile: /var/run/supervisord.pid
#

# source function library
. /etc/rc.d/init.d/functions

RETVAL=0

start() {
    echo -n $"Starting supervisord: "
    daemon "supervisord -c /etc/supervisor/supervisord.conf "
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/supervisord
}

stop() {
    echo -n $"Stopping supervisord: "
    killproc supervisord
    echo
    [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/supervisord
}

restart() {
    stop
    start
}

case "$1" in
  start)
    start
    ;;
  stop) 
    stop
    ;;
  restart|force-reload|reload)
    restart
    ;;
  condrestart)
    [ -f /var/lock/subsys/supervisord ] && restart
    ;;
  status)
    status supervisord
    RETVAL=$?
    ;;
  *)
    echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
    exit 1
esac

exit $RETVAL

将上述脚本内容保存到/etc/rc.d/init.d/supervisor文件中,修改文件权限为755,并设置开机启动

chmod 755 /etc/rc.d/init.d/supervisor
chkconfig supervisor on

注意:修改脚本中supervisor配置文件路径为你的supervisor的配置文件路径

其它Linux发行版开机启动脚本:https://github.com/Supervisor/initscripts

注意:

Supervisor只能管理非daemon的进程,也就是说Supervisor不能管理守护进程。否则提示Exited too quickly (process log may have details)异常。例子中的Tomcat默认是以守护进程启动的,所以我们改成了catalina.sh run,以前台进程的方式运行。

yum方式安装

yum install epel-release
yum install -y supervisor

supervisor没有发布在标准的CentOS源在,需要安装epel源。这种方式安装的可能不是最新版本,但比较方便,安装完成之后,配置文件会自动帮你生成。

默认配置文件:/etc/supervisord.conf
进程管理配置文件放到:/etc/supervisord.d/目录下即可

默认日志文件:/tmp/supervisord.log,可以查看进程的启动信息

Linux 一台服务器部署多个tomcat

linux系统下安装两个或多个tomcat

编辑环境变量:vi /etc/profile

加入以下代码(tomcat路径要配置自己实际的tomcat安装目录)

##########first tomcat###########

CATALINA_BASE=/usr/local/tomcat
CATALINA_HOME=/usr/local/tomcat
TOMCAT_HOME=/usr/local/tomcat
export CATALINA_BASE CATALINA_HOME TOMCAT_HOME

##########first tomcat############

##########second tomcat##########

CATALINA_2_BASE=/usr/local/tomcat_2
CATALINA_2_HOME=/usr/local/tomcat_2
TOMCAT_2_HOME=/usr/local/tomcat_2
export CATALINA_2_BASE CATALINA_2_HOME TOMCAT_2_HOME

##########second tomcat##########

保存退出。
再输入:source /etc/profile
才能生效。

第一个tomcat,保持解压后的原状不用修改,

来到第二个tomcat的bin目录下
打开catalina.sh ,找到下面红字,

# OS specific support.  $var _must_ be set to either true or false.

在下面增加如下代码

export CATALINA_BASE=$CATALINA_2_BASE
export CATALINA_HOME=$CATALINA_2_HOME

来到第二个tomcat的conf目录下
打开server.xml更改端口:
修改server.xml配置和第一个不同的启动、关闭监听端口。
修改后示例如下:
 

 <Server port="9005" shutdown="SHUTDOWN">                  端口:8005->9005
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
    <Connector port="9080" maxHttpHeaderSize="8192"        端口:8080->9080
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
     enableLookups="false" redirectPort="8443" acceptCount="100"
     connectionTimeout="20000" disableUploadTimeout="true" />
<!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="9009"                                  端口:8009->9009
     enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />

分别进入两个tomcat的bin目录,启动tomcat–./startup.sh
http://localhost:8080http://localhost:9080然后访问 和 都可以看到熟悉的tomcat欢迎界面。

linux sed 多行处理详细总结

在正常情况下,sed将待处理的行读入模式空间,脚本中的命令就一条接着一条的对该行进行处理,直到脚本执行完毕,然后该行被输出,模式空间请空;然后重复刚才的动作,文件中的新的一行被读入,直到文件处理完备。但是,各种各样的原因,比如用户希望在某个条件下脚本中的某个命令被执行,或者希望模式空间得到保留以便下一次的处理,都有可能使得sed在处理文件的时候不按照正常的流程来进行。这个时候,sed设置了一些高级命令来满足用户的要求。如果想要学习sed的高级命令,首先要了解如下两个缓存区:

1、模式空间(pattern space)的定义:模式空间就是一个缓存区,保存sed刚刚从输入端读取的。
2、暂存空间(hold space)的定义:暂存空间就是在处理模式空间数据的时候,临时缓存数据用的。

还有几个命令参数:

  • g: 将hold space中的内容拷贝到pattern space中,原来pattern space里的内容清除
  • G: 将hold space中的内容append到pattern spacen后
  • h: 将pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除
  • H: 将pattern space中的内容append到hold spacen后
  • x: 交换pattern space和hold space的内容

比如咱们想要倒排一个文件的内容,文件如下:

[[email protected] ~]$ cat tmp
  1-line
  2-line
  3-line

执行如下命令:

[[email protected] ~]$ sed '2,$G;h;$!d' tmp
  3-line
  2-line
  1-line

下面咱们逐步理解上面的执行过程

一、让咱们来分析一下如下三条命令:

  • 2,$G:从第二行到最后一行执行G命令
  • h:执行h命令
  • $!d:删除除了最后一行的所有行

二、具体的操作

1、扫描到第一行

  • 将1-line放入模式空间;此时模式空间还是1-line;
  • 直接执行h命令,此时暂存空间是1-line;
  • 执行d命令,删除了模式空间仅有的一行数据,删除之后,模式空间是空的

2、扫描到第二行

  • 将2-line放入模式空间
  • 执行G命令,将暂存空间的1-line添加到模式空间2-line的后面,此时模式空间是2-linen1-line;
  • 执行h命令,此时暂存空间的内容是2-linen1-line;
  • 执行d命令,模式空间被清空

3、扫描到第三行

  • 将3-line放入模式空间,
  • 执行G命令,将暂存空间的2-linen1-line添加到模式空间3-line的后面,此时模式空间是3-linen2-linen1-line;
  • 执行h命令,此时暂存空间的内容是3-linen2-linen1-line;
  • 不执行$!d;

4、直接输出 3-linen2-linen1-line

  • 当然,命令:sed ‘1!G;h;$!d’ tmp 也能有这个效果。

linux下nginx不支持中文URL路径的解决方案

未分类

1、确定你的系统是UTF编码

[root@localhost ~]# echo $LAGN
en_US.UTF-8

2、nginx配置文件里默认编码设置为utf-8

server
{
listen 80;
server_name .inginx.com ;
index index.html index.htm index.php;
root /usr/local/nginx/html/inginx.com;
charset utf-8;
}

3、将非UTF-8的文件名转换为UTF-8编码

做法很简单,把文件名都修改成utf8编码就可以了!

安装convmv,由他去转换编码:

yum install convmv -y
convmv -f GBK -t UTF8 -r --notest 目标路径

其中-f是源编码,-t是目标编码,-r是递归处理目录,–notest是不移动,实际上对文件进行改名。

Linux – 将memcached注册为服务

1、编写脚本

编写脚本文件如下(memcached):

#!/bin/sh
#
# memcached: Start/Stop/Restart memcached
# chkconfig: 35 33 84
# description: memcached server
MEMCACHED=/usr/local/bin/memcached
# memcached 分配的内存大小,单位M
MEMSIZE=128
USER=nobody

# memcached使用的端口
PORT01=11211
# 每个memcache 提供的最大连接数
MAXCONN=1024
# 每个memcache 的进程ID
PID01=/var/run/memcached/memcached$PORT01.pid
RETVAL=0
prog="memcached"

start() {
         echo -n $"Starting $prog: "
         $MEMCACHED -d -m $MEMSIZE -u $USER -p $PORT01 -c $MAXCONN -P $PID01
     if [ $? -eq 0 ];then
            echo "memcacheds$PORT01 servers is start ok..."
         else
            echo "memcacheds$PORT01 server not runing......"
         fi

        }

stop() {

      for i in $PID01
      do 
       kill `cat $i`
       rm -f $i
           echo  $"Stopping $prog: "
      done

     }

# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart}"
;;
esac
exit $RETVAL

2、将其放入/etc/init.d/目录下

3、为文件赋予被执行的权限

chmod /etc/init.d/memcached

4、将memcached加入chkconfig管理列表

执行命令:

chkconfig --add memcached

chkconfig memcached on

5、启动memcached服务

service memcached start