# RPM 软件管理程序:rpm

# RPM 默认安装的路径

一般来说,RPM 类型的文件在安装的时候,会先读取文件内记载的设置参数内容,然后将该数据用来对比 Linux 系统的环境,找出未安装的依赖软件。

若环境检查合格了,则开始安装。安装完成后,该软件相关的信息会被写入到 /var/lib/rpm/ 目录下的数据库文件中。

这个数据库的数据很重要,因为未来如果我们有任何软件的升级需求,版本之间的比较就是来自这个数据库,想查询已安装的软件信息也是来自于该数据库,同时,目前的 RPM 也提供数字签名信息,也是记录在此

那么软件内的文件放置到哪里的?这个与文件系统有关,在第 5 章的目录配置谈过每个目录的含义,这里再次强调:

  • /etc/:一些配置文件
  • /usr/bin/:一些可执行文件
  • /usr/lib/:一些程序使用的动态函数库
  • /usr/share/doc/:一些基本的软件使用手册与说明文件
  • /usr/share/man/:一些 man page 文件

# RPM 安装(install)

因为软件安装时 root 的工作,因此需要有 root 身份才可以使用 rpm 指令

rpm -ivh package_name

-i:install
-v:查看更详细的安装信息画面
-h:以安装信息列显示安装进度
1
2
3
4
5
# 范例 1:安装原版光盘上的 rp-pppoe 软件
[root@study ~]# rpm -ivh /mnt/Packages/rp-pppoe-3.11-7.el7.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:rp-pppoe-3.11-7.el7              ################################# [100%]
   
# 范例 2:一次性安装两个以上的软件
rpm -ivh a.i386.rpm b.i386.rpm *.rpm
# 后面可以接上许多的软件

# 范例 3:直接有网络上面的某个文件安装
rpm -ivh http://website.name/path/pkgname.rpm
1
2
3
4
5
6
7
8
9
10
11
12

另外,如果在安装过程中发现问题,或已经知道会发生问题,还是要强制安装,可以参考以下说明,下面列出 rpm 安装时常用的选项与参数说明:

  • --nodeps

    • 使用时机:当发生软件属性依赖问题而无法安装时,但你想强制安装时
    • 危险性:如果不考虑依赖问题,可能导致软件无法正常使用
  • --replacefiles

    • 使用时机:如果在安装过程中出现了「某个文件已经被安装在你的系统上」的信息,又或许出现版本不合的信息(confilcting files)时,可以使用该参数来直接覆盖文件
    • 危险性:覆盖的动作无法还原,所以你必须很清楚的知道你自己在做什么
  • --replacepkgs

    使用时机:重新安装某个已经安装过的软件,如果你要安装一堆 RPM 软件时,可以使用 rpm -ivh *.rpm,但若某些软件已经安装过了,此时系统会出现某软件已经安装过的信息,导致无法继续安装。此时可以使用该选项

  • --force

    使用时机:该参数其实是 --replacefiles--replacepkgs 的合体

  • --test

    使用时机:想要测试下该软件是否可以被安装到使用者的 Linux 环境中,可以找出是否有属性依赖问题

  • --justdb

    使用时机:由于 RPM 数据库破损或某些缘故产生错误时,可以使用该选项来更新软件在数据库内的相关信息

  • --nosignature

    使用时机:想要忽略数字签名时的检查时

  • --prefix 新路径

    使用时机:要将软件安装到其他非正规目录时

  • --noscripts

    • 使用时机:不想让该软件在安装过程中自行执行某些系统指令
    • 说明:RPM 的优点除了可以将文件放置到指定位置外,还可以自动执行一些前置作业指令,例如数据库初始化。如果不想让 RPM 帮你自动执行这一类的指令,可以加上该参数

一般来说,rpm 的安装选项与参数大约就是以上的项目。作者建议一般使用 -ivh 就好了。如果安装过程中发现问题,一个一个将问题找出来,尽量不要使用暴力安装法(不要使用 -force 方式)

范例:当没有网络时,通过原版光盘安装一个名为 pam-devel 软件时,可以如下做

找出光驱位置:blkid 
挂载光盘:mount /dev/sr0 /mnt
找出文件的实际路径:find /mnt -name 'pam-devel*'
测试此软件是否具有相依性:rpm -ivh pam-devel... --test
直接安装:rpm -ivh pam-devel...
卸载光盘:umount/mnt
1
2
3
4
5
6

# RPM 升级与更新(upgrade/freshen)

使用 RPM 来升级也很简单,可以使用如下参数

  • -Uvh

    后面接的软件即使没有安装过,则系统直接安装;若安装过旧版的软件,则系统自动更新至新版

  • -Fvh

    后面接的软件并未安装到系统,则该软件不会安装;

从说明来看,-Fvh 一般用在大量升级系统旧版本软件时。

早期没有 yum 的环境下,同时网络带宽也很糟糕的情况下,通常有的朋友在进行整个操作系统的旧版本软件修补时,喜欢这么做:

  1. 先到个发展商 errdata 网站或者是国内的 FTP 镜像下载最新的 RPM 文件
  2. 使用 -Fvh 将你系统内曾安装过的软件进行升级

# RPM 查询(query)

RPM 在查询的时候,其实也是使用的是 /var/lib/rpm 目录下的数据库文件

另外,还可以查询未安装的 RPM 文件内的信息。

rpm -qa																	  # 已安装软件
rpm -q[licdR] 已安装的软件名称							# 已安装软件
rpm -qf 存在于系统上面的某个文件名						# 已安装软件
rpm -qp[licdR] 未安装的某个文件名					# 查询 RPM 文件

选项与参数:
查询已安装软件的信息:
	-q:仅查询,后面接的软件名称是否有安装
	-qa:列出所有的,已经安装在本机所有软件名称
	-qi:列出该软件的详细信息(information),包含开发商、版本与说明等
	-ql:列出该软件所有的文件与目录所在完整文件名(list)
	-qc:列出该软件的所有配置文件(找出在 `/etc/` 下的文件名)
	-qd:列出该软件的所有说明文件(找出与 man 有关的文件)
	-qR:列出与该软件有关的相依赖软件所含的文件(Required)
	-qf:由后面接的文件名,找出该文件属于哪一个已安装的软件
	-q --scripts:列出是否含有安装后需要执行的脚本文件,可以用来 debug
查询某个 RPM 文件内含有的信息:
	-qp[icdlR]:这里的参数与上面的一致,只是这里查询的是没有安装的软件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

在查询部分,所有参数都需要加上 -q 表示查询。查询主要分为两部分:

  • 查询已安装到系统上的软件信息,数据信息由 /var/lib/rpm/ 提供
  • 查询 rpm 文件内容,等于是由 RPM 文件内找出一些要写入数据库内的信息,需要使用 -qp(p 是 package 的含义)
# 范例 1:找出是否有安装 logrotate 这个软件
[root@study ~]# rpm -q logrotate
logrotate-3.8.6-17.el7.x86_64
# 查询未安装的,则提示没有安装
[root@study ~]# rpm -q logrotating
package logrotating is not installed

# 范例 2:列出上题中,属于该软件所提供的所有目录与文件
[root@study ~]# rpm -ql logrotate
/etc/cron.daily/logrotate
/etc/logrotate.conf
...
# 可以看到有很多的文件和目录,可以用来追踪软件的数据

# 范例 3:列出 logrotate 软件的相关说明
[root@study ~]# rpm -qi logrotate
Name        : logrotate										# 软件名称
Version     : 3.8.6												# 软件版本
Release     : 17.el7											# 释出的版本
Architecture: x86_64											# 编译时所针对的硬件等级
Install Date: Fri Oct  4 18:22:43 2019		# 该软件安装到本系统的时间
Group       : System Environment/Base			# 软件是放在哪一个软件群组中
Size        : 107156											# 软件的大小
License     : GPL+												# 释出的授权方式
Signature   : RSA/SHA256, Mon Nov 12 22:39:25 2018, Key ID 24c6a8a7f4a80eb5
Source RPM  : logrotate-3.8.6-17.el7.src.rpm	# SRPM 的文件名
Build Date  : Wed Oct 31 03:13:00 2018				# 软件编译打包的时间
Build Host  : x86-01.bsys.centos.org					# 在哪一部主机上编译的
Relocations : (not relocatable)
Packager    : CentOS BuildSystem <http://bugs.centos.org>
Vendor      : CentOS
URL         : https://github.com/logrotate/logrotate
Summary     : Rotates, compresses, removes and mails system log files
Description :		# 详细描述
The logrotate utility is designed to simplify the administration of
log files on a system which generates a lot of log files.  Logrotate
allows for the automatic rotation compression, removal and mailing of
log files.  Logrotate can be set to handle a log file daily, weekly,
monthly or when the log file gets to a certain size.  Normally,
logrotate runs as a daily cron job.

Install the logrotate package if you need a utility to deal with the
log files on your system.
# 列出了很多的信息

# 范例 4:分别仅找出 logrotate 的配置文件与说明文件
[root@study ~]# rpm -qc logrotate
/etc/cron.daily/logrotate
/etc/logrotate.conf
/etc/rwtab.d/logrotate
[root@study ~]# rpm -qd logrotate
/usr/share/doc/logrotate-3.8.6/CHANGES
/usr/share/doc/logrotate-3.8.6/COPYING
/usr/share/man/man5/logrotate.conf.5.gz
/usr/share/man/man8/logrotate.8.gz

# 范例 5:若要成功安装 logrotate,还需要什么文件的帮忙
[root@study ~]# rpm -qR logrotate
/bin/sh
/bin/sh
config(logrotate) = 3.8.6-17.el7
coreutils >= 5.92
libacl.so.1()(64bit)
libacl.so.1(ACL_1.0)(64bit)
libc.so.6()(64bit)
libc.so.6(GLIBC_2.14)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libc.so.6(GLIBC_2.4)(64bit)
libc.so.6(GLIBC_2.7)(64bit)
libc.so.6(GLIBC_2.8)(64bit)
libpopt.so.0()(64bit)
libpopt.so.0(LIBPOPT_0)(64bit)
libselinux.so.1()(64bit)
popt
rpmlib(CompressedFileNames) <= 3.0.4-1
rpmlib(FileDigests) <= 4.6.0-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rtld(GNU_HASH)
rpmlib(PayloadIsXz) <= 5.2-1
# 列出了该软件的依赖文件

# 范例 6:在范例 5 基础上,找出 /bin/sh 是哪个软件提供的?
[root@study ~]# rpm -qf /bin/sh
bash-4.2.46-33.el7.x86_64
# 参数后,接的是文件,而不是软件名称
# 该功能查询系统的某个文件属于哪一个软件的


# 范例 7:假设我下载一个 RPM 文件,想要知道该文件的需求文件
 rpm -qpR filename.i386.rpm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

# 练习题

  1. 想要知道系统中,以 C 开头的软件有几个

    [root@study ~]# rpm -qa | grep ^c | wc -l
    65
    
    1
    2
  2. www 服务器为 Apache,我知道它使用的 RPM 软件文件名为 httpd,要知道这个软件的所有配置文件放置何处

    [root@study ~]# rpm -qc httpd
    
    1
  3. 承上题,如果查出来的配置文件已经被修改过,但是忘记修改了哪些地方,所以想要直接重新安装一次软件

    假设该软件在网络上的地址为:http://xxx.com/path/httpd-x.x.xx.i386.rpm
    rpm -ivh http://xxx.com/path/httpd-x.x.xx.i386.rpm --replacepkgs
    
    1
    2
  4. 如果误删了某个重要文件,如 /etc/crontab ,但不知道它属于哪一个软件,怎么办?

    [root@study ~]# rpm -qf /etc/crontab 
    crontabs-1.11-6.20121102git.el7.noarch
    
    1
    2

# RPM 验证与数字签名(Verify、signature)

验证功能主要作用是使用 /var/lib/rpm 下的数据库内容来比对目前 LInux 系统的环境下的偶有软件文件,是否有被修改过(笔者猜测可能是和原始安装文件中的文件对比?)

rpm -Va
rpm -V 已安装的软件名称
rpm -Vp 某个 RPM 文件的文件名
rpm -Vf 在系统上的某个文件

选项与参数:
	-V:后面加的是软件名称,若该软件所含的文件被修改过,才会列出来
	-Va:列出目前系统上所有可能被修改过的文件
	-Vp:后面加的是文件名,列出该软件内可能被修改过的文件
	-Vf:列出某个文件是否被修改过
1
2
3
4
5
6
7
8
9
10
# 范例 1:列出你的 Linux 内的 logrotate 软件是否被修改过
[root@study ~]# rpm -V logrotate
# 没有任何信息,表示没有被修改过

# 范例 2:查询下 /etc/crontab 是否被修改过
[root@study ~]# rpm -Vf /etc/crontab 
S.5....T.  c /etc/crontab
# 因为被更改过,所以列出更改过的信息类型
1
2
3
4
5
6
7
8

你是否有一个疑问?哪些文件是可以被用来查询是否有修改过的?还记得 rpm 的-ql:列出该软件所有的文件与目录所在完整文件名(list)?下面就来实践下

[root@study ~]# rpm -ql logrotate
/etc/cron.daily/logrotate
/etc/logrotate.conf
/etc/logrotate.d
/etc/rwtab.d/logrotate
/usr/sbin/logrotate
/usr/share/doc/logrotate-3.8.6
/usr/share/doc/logrotate-3.8.6/CHANGES
/usr/share/doc/logrotate-3.8.6/COPYING
/usr/share/man/man5/logrotate.conf.5.gz
/usr/share/man/man8/logrotate.8.gz
/var/lib/logrotate
/var/lib/logrotate/logrotate.status
# 该软件一共有 12 个文件,修改 /etc/logrotate.conf 内的 rotate 变成 6

# 再看看该软件有哪些文件被修改过了
[root@study ~]# rpm -V logrotate
..5....T.  c /etc/logrotate.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

文件名前面有一个 c 表示是 configuration (配置文件),前面一堆的含义如下:

  • S:file Size differs,文件的容量大小已经改变
  • M:Mode differs,文件的类型或文件的属性(rwx)已经改变
  • 5:MD5 sum differs,MD5 指纹码的内容已经改变
  • D:Device major/minor number mis-match,设备的主/次代码已经改变
  • L:readLink(2) path mis-match,Link 路径已经改变
  • U:User ownership differs,文件的所属人已经改变
  • G:Group ownership differs,文件的所属群组已被改变
  • T:mTime differs,文件的建立时间已被改变
  • P:caPabilities differ,功能已经改变

所以当一个配置文件的所有信息都被修改过,则会显示 SM5DLUGTP c filename

文件名前面的 c 表示是文件类型,有以下几类:

  • c:配置文件 config file
  • d:文件数据文件 documentation
  • g:鬼文件 ghost file,通常是该文件不被某个软件包含,较少发生
  • l:许可证文件 license file
  • r:自述文件 read me

通过该功能,如果这些修改是预期中的,就是正常的,比如你的 binary progran 都被修改过了,那么就要小心了(作者通过 rpm -Va 找出来好多 binary program 被修改过,被黑了,当成了跳板机)

# 数字签名(digital signature)

首先,安装软件时,去对比官方释出的 MD5 指纹,能对上则表示是官方释出的,但是 MD5 也可能被串改?用数字签名来校验软件的来源

厂商可以数字签名系统产生一个专属于该软件的签章,并将该签章的公钥(public key)释出,当安装一个 RPM 软件时:

  1. 首先比如要先安装原厂释出的公钥文件
  2. 实际安装原厂的 RPM 软件时,rpm 指令会去读取 RPM 文件的签章信息,与本机系统内的签章信息比对
  3. 若签章相同则安装,若找不到相关的签章信息时,则给予警告并且停止安装

CentOS 使用的数字签名系统为 GNU 计划的 GnuPG(GNU Privacy Guard)。有兴趣可以去详细了解下 GPG 的加密机制,这里简单的说明数字签名在 RPM 文件上的应用。

那么首选比如安装原厂释出的 GPG 数字签名的公钥文件,CentOS 的数字签名位于

[root@study ~]# ll /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 
-rw-r--r--. 1 root root 1690 95 2019 /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[root@study ~]# cat /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBFOn/0sBEADLDyZ+DQHkcTHDQSE0a0B2iYAEXwpPvs67cJ4tmhe/iMOyVMh9
...
=OGYX
-----END PGP PUBLIC KEY BLOCK-----
1
2
3
4
5
6
7
8
9
10

那么该文件可以通过如下的方式来安装

[root@study ~]# rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
1

由于不同版本 GPG 密钥文件放置的位置可能不同,不过大多是以 GPG-KEY 来命名的,可以简单时候 locate 或 find 来寻找

[root@study ~]# locate GPG-KEY
[root@study ~]# find /etc -name '*GPG-KEY*'
1
2

安装完成后,这个密钥的内容基本上以 pubkey 的软件名称来呈现

[root@study ~]# rpm -qa | grep pubkey
gpg-pubkey-f4a80eb5-53a7ff4b
[root@study ~]# rpm -qi gpg-pubkey-f4a80eb5-53a7ff4b
Name        : gpg-pubkey
Version     : f4a80eb5
Release     : 53a7ff4b
Architecture: (none)
Install Date: 2020年04月05日 星期日 16时21分30秒
Group       : Public Keys
Size        : 0
License     : pubkey
Signature   : (none)
Source RPM  : (none)
Build Date  : 2014年06月23日 星期一 18时19分55秒
Build Host  : localhost
Relocations : (not relocatable)
Packager    : CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>
Summary     : gpg(CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>)
Description :
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: rpm-4.11.3 (NSS-3)

mQINBFOn/0sBEADLDyZ+DQHkcTHDQSE0a0B2iYAEXwpPvs67cJ4tmhe/iMOyVMh9
...
=OGYX
-----END PGP PUBLIC KEY BLOCK-----
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

重点是最后面出现的一串数据,如果你忘记加上数字签名,很多原版软件就不能让你安装,除非使用 rpm 时选择忽略数字签名的选项

笔者疑问:这个数值签名是系统自动安装的,是随机的吗?那么多版本的系统和软件,难道都公用同一个?这个笔者有点想不通

# RPM 卸载与重建数据库(erase/rebuilddb)

卸载软件,要注意的是,由最上层往下卸载,啥意思?由于有函数库软件依赖等原因,要正常卸载的话,只能卸载掉一个没有被依赖的软件或则函数库,有依赖的就会导致无法卸载。下面一个案例说明

# 1. 好处与 pam 有关的软件名称,并尝试移除 pam 软件
[root@study ~]# rpm -qa | grep pam
fprintd-pam-0.8.1-2.el7.x86_64
gnome-keyring-pam-3.28.2-1.el7.x86_64
pam-1.1.8-22.el7.x86_64

[root@study ~]# rpm -e pam 
error: Failed dependencies: # 检测到有很多软件依赖了它,不能删除
	libpam.so.0()(64bit) is needed by (installed) libpwquality-1.2.3-5.el7.x86_64
	libpam.so.0()(64bit) is needed by (installed) libuser-0.60-9.el7.x86_64
	libpam.so.0()(64bit) is needed by (installed) passwd-0.79-5.el7.x86_64
	libpam.so.0()(64bit) is needed by (installed) util-linux-2.23.2-61.el7.x86_64
	
# 2. 若移除 rp-pppoe 软件就可以
# rp-pppoe 软件是本章练习安装的,所以没有任何软件依赖它
[root@study ~]# rpm -e rp-pppoe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

由于 RPM 文件常常会安装、移除、升级等,某些动作可能会导致 RPM 数据库 /var/lib/rpm/ 内的文件破损。此时你可以重建它

rpm --rebuilddb   # 重建数据库
1