CentOS 软件包 rpm 管理学习笔记
目录
-
CentOS 软件包 rpm 管理学习笔记 - 1. 软件运行和编译
- 1.1 软件相关概念
- 1.1.1 ABI
- 1.1.2 API
- 1.2 C 语言程序编译过程
- 1.3 软件模块的静态和动态链接
- 1.3.1 静态链接的特点
- 1.3.2 动态链接的特点
- 1.3.3 模块(库)文件
- 2. 软件包和包管理工具
- 2.1 软件包介绍
- 2.1.1 软件包中文件分类
- 2.1.2 程序包管理器
- 2.1.3 包命名
- 2.1.4 分类和拆包
- 2.1.5 包之间的依赖
- 2.1.6 包管理器相关文件
- 2.1.7 获取程序包的途径
- 3. 包管理器
- 3.1 安装和升级
- 3.2 查询
- 3.2.1 包选择选项(部分)
- 3.2.2 包查询选项(部分)
- 3.3 卸载
- 3.4 校验
- 3.4.1 检查包的完整性和签名
- 3.4.2 rpm 校验命令的通用格式:
- 3.5 rpm数据库
CentOS 软件包 rpm 管理学习笔记
以下所涉及的基本上以CentOS 8系统为基础。
1. 软件运行和编译
1.1 软件相关概念
1.1.1 ABI
ABI 即 Application Binary Interface 应用程序二进制接口。
windows 与 Linux 之间是不兼容的:
- Linux --> ELF (Executable and Linkable Format)
- Windows --> PE (Portable Executable)
想要在不同的系统上运行其他系统,需要库级别的虚拟化:
- Linux --> WINE
- Windows --> Cygwin
1.1.2 API
API : Application Programming Interface,应用程序编程接口。由于操作系统不同,因此又细分为:Windows API 和 Linux API。相互之间不兼容,为了解决这个问题,提出了 POSIX 标准。
POSIX: Portable Operating System Interface. 可移植操作系统接口。
1.2 C 语言程序编译过程
C 源代码 --> 预处理 --> 编译 --> 汇编 --> 链接
gcc 编译过程:
# 分步编译运行
gcc -E hello.c -o hello.i # 对hello.c进行预处理,生成 hello.i 文件
gcc -S hello.i -o hello.s # 对预处理过的文件进行编译,生成汇编文件
gcc -c hello.s -o hello.o # 对汇编文件进行编译,生成目标文件
gcc hello.o -o hello # 对目标文件进行链接,生成可执行文件
# 可一步实现编译
gcc hello.c -o hello # 直接编译链接成可执行文件
1.3 软件模块的静态和动态链接
链接的主要作用:使各个模块之间的相互引用能够正常地调用。分为静态链接和动态链接。
1.3.1 静态链接的特点
- 把程序对应的依赖库复制一份过来
- 生成模块文件 libxxx.a
- 嵌入程序包
- 升级难,需要重新编译
- 占用较多空间,迁移容易
1.3.2 动态链接的特点
- 只把依赖库做成一个动态链接
- 生成模块文件 libxxx.so
- 链接指向
- 占用较少空间,升级方便
1.3.3 模块(库)文件
使用 ldd
可以查看命令所依赖的动态库列表
ldd /bin/cat
管理及查看本机装载的库文件
# 加载配置文件中指定的库文件
ldconfig
# 显示本机已经缓存的所有可用库名及其文件路径映射关系
/sbin/ldconfig -p
配置文件:
/etc/ld.so.conf
/etc/ld.so.conf.d/*.conf
缓存文件:
/etc/ld.so.cache
2. 软件包和包管理工具
2.1 软件包介绍
开源软件最初只提供了 ‘.tar.gz’ 格式的源代码文件,用户必须自己进行编译。后来,Debian 诞生时,推出一个包管理工具 dpkg,用于管理 deb 后缀的包文件。后续其他发行版也推出一些管理工具。
2.1.1 软件包中文件分类
- 二进制文件
- 库文件
- 配置文件
- 帮助文件
示例:利用 cpio 工具查看包文件列表
rpm2cpio pkg-file.rpm | cpio -itv # 预览包内文件
rpm2cpio pkg-file.rpm | cpio -id # "*.conf" 释放包内文件
2.1.2 程序包管理器
其功能是:将编译好的应用程序根据其组成部分打包成一个或多个程序包文件,从而实现程序的安装、查询、升级、卸载和校验等管理操作。
主流的包管理器有:
- redhat:rpm 文件,rpm 包管理器
- debian:deb 文件,dpkg 包管理器
2.1.3 包命名
包命名是有规范的,例如
# 源代码打包后的文件命名格式
name-Version.tar.gz|bz2|xz
Version: major.minor.release
rpm 包命名格式
name-Version-release.arch.rpm
release: release.OS
xz-5.2.4-3.el8.x86_64.rpm
其中 ‘xz’ 是文件名称,‘5.2.4’ 是软件的版本,‘3’ 表示打包的次数,‘el8’ 表示红帽8,'x86_64’代表CPU架构。
常见的架构 arch:
- x86: i386, i486, i586
- x86_64: x64, x86_64, amd64
- powerpc: ppc
- 与平台无关:noarch
如果一个软件体积比较大,可能会拆分成几个文件,例如:
ls httpd*
httpd-2.4.37-16.module_el8.1.o...
httpd-devel-2.4.37...
httpd-filesystem-2.4.37 ...
httpd-manual-2.4.37...
httpd-tools-2.4.37...
2.1.4 分类和拆包
包的分类:
- Application-Version-Arch.rpm: 主包
- Application-devel-Version-Arch.rpm: 开发子包
- Application-utils-Version-Arch.rpm: 工具子包
- Application-libs-Version-Arch.rpm: 库子包
2.1.5 包之间的依赖
包与包之间可能存在相互依赖关系,甚至是循环依赖关系。因此安装包变成很麻烦。为了解决这个问题,开发出相应的管理工具:
- yum (Yellow dog Updater): rpm 包管理器的前端工具
- dnf (Dandified Yum):Fedora 18+ rpm 包管理器的前端工具,在CentOS 8 之后替换 yum
- apt (Advanced Packaging Tool):deb 包管理器的前端工具
- zypper: suse 上的 rpm 前端管理工具
2.1.6 包管理器相关文件
-
包文件组成(每个包独有)
- 包内的文件
- 元数据,例如,包名,版本,依赖,描述等
- 可能有包安装或卸载时运行的脚本,例如可能需要创建运行的账号
-
数据库(公共):/var/lib/rpm,这个数据记录安装后的软件信息
- 程序包名及版本
- 依赖关系
- 功能说明
- 包安装后生成的各个文件路径及校验信息
2.1.7 获取程序包的途径
软件包可以从系统发行的光盘或官方网站获取。
CentOS 镜像
https://www.centos.org/download/
https:mirrors.aliyun.com/
https:mirrors.sohu.com
https:mirrors.163.com
Ubuntu 镜像
https://cdimage.Ubuntu.com/release
https://releases.Ubuntu.com
第三方组织提供
# Fedora-EPEL: Extra Packages for Enterprise Linux
https://fedoraproject.org/wiki/EPEL
https:mirrors.aliyun.com/epel/?...
# Rpmforge: 官网 红帽推荐,包齐全,将将关闭
https://repoforge.org/
# Community Enterprise Linux Repository 支持最新的内核和硬件相关包
https:www.elrepo.org
软件项目的官方站点,例如,mariandb,mysql,apache 等。
搜索引擎
http://pkgs.org
http://rpmfind.net
http://rpm.pbone.net
https://sourceforge.net
注意:第三方包建议要检查包源合法性及包的完整性。
自己制作:利用工具将源码文件制作成rpm包。
3. 包管理器
CentOS 系统上使用 rpm (Redhat Package Manager, RPM Package Manager) 命令程序包。其功能:安装、卸载、升级、查询、校验及本地记录安装情况的数据库维护。
rpm 命令比较多,这是通用选项:
选项 | 说明 |
---|---|
-?, --help | 打印比常规更长的使用信息 |
–version | 打印包含正在使用的 rpm 版本号 |
–quiet | 尽可能不打印信息,通常只显示错误消息 |
-v, --verbos | 打印详情 - 通常显示程序处理消息 |
-vv | 打印许多丑陋的调试信息 |
–rcfile FILELIST | 替换要读取的配置文件列表。以冒号分隔的 FILELIST 中的每个文件都由 rpm 依次读取,成为其配置信息。必须提供一个文件。默认的 FILELIST 是 /usr/lib/rpm/ rpmrc:/usr/lib/rpm/redhat/rpmrc:/etc/rpmrc:~/.rpmrc |
–macros FILELIST | 替换要加载的宏文件列表 |
–pip CMD | 通过管道将 rpm 输出传送到命令 CMD |
–dbpath DIRECTORY | 使用 DIRECTORY 中的数据库,而不是默认的路径 /var/lib/rpm |
–root DIRECTORY | 所有操作都以 DIRECTORY 为根的文件系统树。这意味着在 DIRECTORY 中的数据库将用于依赖性检查,且任何脚本(例如,安装时 %post,构建包时的 %prep)都会在 chroot(2) 到 DIRECTORY 之后运行 |
-D, --define=‘MACRO EXPR’ | 把 MACRO 定义为 EXPR 的值 |
–undefine=‘MACRO’ | 取消定义 MACRO |
-E, --eval=‘EXPR’ | 打印 EXPR 的宏扩展 |
3.1 安装和升级
目前直接使用rpm进行安装、升级及删除时不方便,难以解决依赖问题。但是,我们需要用它来查询有关安装包的信息。
格式:
# 安装命令的通用格式,安装新包
rpm {-i|--install} [install-options] PACKAGE-FILE...
# 升级命令的通用格式,能升级或安装新包
rpm {-U|--upgrade} [upgrade-options] PACKAGE-FILE...
# 只升级版本较早的包
rpm {-F|--freshen} [install-options] PACKAGE-FILE...
# 重新安装
rpm {--reinstall} [install-options] PACKAGE-FILE...
常用选项:
选项 | 说明 |
---|---|
–allfiles | 安装或升级所有包的 missingok(缺失了也不警告) 文件,无论它们是否存在 |
–force | 与用时使用 --replacepkgs, --replacefiles 和 --oldpackage 一样 |
-h, --hash | 当解压包归档时打印50个井号。与 -v 一起使用时显示更好 |
–justdb | 只升级数据库,不升级文件系统 |
–nodeps | 在升级或安装时,不做依赖性检查 |
–noscripts | 不执行脚本 |
–oldpackage | 允许降级到旧版本 |
–percent | 当文件从归档包中解压时打印百分比 |
–prefix NEWPATH | 对于可重新定义安装位置的二进制包而言,可以把以安装前缀开头的所有文件路径都转换到新的位置 NEWPATH |
–relocate OLDPATH=NEWPATH | 对于可重新定义安装位置的二进制包,则把所有以 OldPath 开头的文件路径转换成 NEWPATH |
–test | 不安装包,仅检测和报告潜在的冲突 |
–replacepkgs | 即使包中的一些文件已经安装在系统上,也能安装该包 |
–replacefiles | 安装该包,即使它们取代从其他已经安装包时生成的文件 |
安装时常用的选项组合是:
rpm -ivh pkg-file...
rpm -Uvh pkg-file...
rpm -Fvh pkg-file...
升级时注意事项:
- 不要对内核进行升级,Linux 支持多内核版本共存,因此推荐直接安装新版本内核
- 如果原包的配置文件在安装后有过修改,则升级时,新版的同一个配置文件不会覆盖现有文件,而是把新版配置文件进行重命名(filename.rpmnew)。
3.2 查询
对于rpm命令而言,最大的作用就是用于查询。查询功能依赖数据库:/var/lib/rpm
rpm 查询命令的通用格式:
rpm {-q|--query} [select-options] [query-options]
我们可以通过以下命令来安装软件:
rpm -q ncompress &> /dev/null || dnf install -y ncompress
您可以指定要打印的包信息的格式。想要达到此目的,使用以下选项:
# QUERYFMT 是格式字符串,是标准 printf(3) 格式的修订版。
--qf|--queryformat QUERYFMT
rpm查询命令有两个查询选项子集:包选择和信息选择。
3.2.1 包选择选项(部分)
选项 | 说明 |
---|---|
PACKAGE-NAME | 查询已安装的名为 PACKAGE-NAME 的包 |
-a, --all [SELECTOR] | 查询所有已安装的包。可选以 tag=pattern 格式的 SELECTOR 提供缩小选择范围,例如,name=“b*” 查询以 “b*” 开头的包名 |
–dupes | 列出重复的包 |
-f, --file FILE | 查询属于名称为 FILE 的包 |
–filecaps | 列出兼容 POSIX1.e 的文件名 |
–fileclass | 列出带其类的文件名(libmagic 分类) |
–filecolor | 列出带有对应颜色的文件名(0 表示无架构,1 表示 32 位,2 表示 64 位) |
–fileprovide | 列出文件名及其提供者 |
–filerequire | 列出文件名及其依赖包 |
-g, --group GROUP | 查询包及其 GROUP 组 |
-p, --Package PACKAGE-FILE | 查询一个(未安装的)包 PACKAGE-FILE。PACKAGE-FILE 可以指定为 ftp 或 http 样式的 URL,这样包头将会被下载和查询到。 |
–whatobsoletes CAPABILITY | 查询所有过时的 CAPABILITY 的包,确保正常功能 |
–whatprovieds CAPABILITY | 查询能提供 CAPABILITY 能力的所有包 |
–whatrequired CAPABILITY | 查询所有需要 CAPABILITY 才能正常运行的包 |
–whatconflicts CAPABILITY | 查询所有与 CAPABILITY 冲突的包 |
–whatrecommends CAPABILITY | 查询所有建议 CAPABILITY 的包 |
–whatsupplements CAPABILITY | 查询所有实现 CAPABILITY 的包 |
–whatenhances CAPABILITY | 查询所有加强 CAPABILITY 的包 |
备注:以上出现的 CAPABILITY 一般是指包名的关键字。例如:
# 查询 bash 由那个包提供
rpm -q --whatprovides bash
bash-4.4.20-2.el8.x86_64
# 查询那些包依赖 bash
rpm -q --whatrequires bash
ca-certificates-2021.2.50-80.0.el8_4.noarch
dracut-049-191.git20210920.el8.x86_64
initscripts-10.00.15-1.el8.x86_64
rsyslog-8.2102.0-5.el8.x86_64
bash-completion-2.7-5.el8.noarch
只想查询该包的配置文件:
rpm -qc bash
/etc/skel/.bash_logout
/etc/skel/.bash_profile
/etc/skel/.bashrc
查询版本更新的日志:
rpm -q --changelog
查询在安装包前或后执行的脚步,可以分成四类,即安装前后脚本,卸载前后脚本:
pre 表示前,post 表示后。以下示例中有:postinstall 和 postuninstall。
rpm -q --scripts bash
postinstall scriptlet (using <lua>):
nl = '\n'
sh = '/bin/sh'..nl
bash = '/bin/bash'..nl
f = io.open('/etc/shells', 'a+')
if f then
local shells = nl..f:read('*all')..nl
if not shells:find(nl..sh) then f:write(sh) end
if not shells:find(nl..bash) then f:write(bash) end
f:close()
end
postuninstall scriptlet (using <lua>):
-- Run it only if we are uninstalling
......
rpm -q --scripts httpd
postinstall scriptlet (using /bin/sh):
if [ $1 -eq 1 ] ; then
# Initial installation
systemctl --no-reload preset httpd.service htcacheclean.service httpd.socket &>/dev/null || :
fi
preuninstall scriptlet (using /bin/sh):
if [ $1 -eq 0 ] ; then
# Package removal, not upgrade
systemctl --no-reload disable --now httpd.service htcacheclean.service httpd.socket &>/dev/null || :
fi
postuninstall scriptlet (using /bin/sh):
# Trigger for conversion from SysV, per guidelines at:
# https://fedoraproject.org/wiki/Packaging:ScriptletSnippets#Systemd
posttrans scriptlet (using /bin/sh):
test -f /etc/sysconfig/httpd-disable-posttrans || \
/bin/systemctl try-restart --no-block httpd.service htcacheclean.service >/dev/null 2>&1 || :
查询指定包具有那些文件或命令等:
rpm -q --provides bash
/bin/bash
/bin/sh
bash = 4.4.20-2.el8
bash(x86-64) = 4.4.20-2.el8
config(bash) = 4.4.20-2.el8
示例,如果想要查询含有 ‘http’ 的包是否已经安装
rpm -qa | grep http
libnghttp2-1.33.0-3.el8_2.1.x86_64
# 或者
rpm -qa "*http*"
libnghttp2-1.33.0-3.el8_2.1.x86_64
3.2.2 包查询选项(部分)
选项 | 说明 |
---|---|
-d, --artifactfiles | 仅列出 artifact 文件(暗示 -l) |
–changelog | 显示包的改变的信息 |
–changes | 显示带有完整时间戳的包的包的改变信息 |
-c, --configfiles | 仅列出配置文件(暗示 -l) |
–conficts | 列出该包与之冲突的功能 |
-d, --docfiles | 仅列出帮助文档文件(暗示 -l) |
–dump | 导出按照以下顺序的文件信息:path size mtime digest mode owner group isconfig isdoc rdev symlink |
–enhances | 列出包所增强的功能 |
–filesbypkg | 列出每个选择的包中所有文件 |
–filetriggers | 列出包中文件触发脚本 |
-i, --info | 显示包的信息,包括名称,版本和描述。如果只是指定了一个,将使用 --queryformat |
–last | 按照安装的时间顺序对包排序,最后安装的包在顶部 |
-l, --list | 列出包中的文件 |
–obsoletes | 列出过时的包 |
–provides | 列出该包支持的功能 |
–recommends | 列出包所推荐的功能 |
-R, --requires | 列出该包所依赖的功能 |
–suggests | 列出包所建议的功能 |
–supplements | 列出包所实现的功能 |
–scripts | 列出作为安装或卸载进程中使用的该包指定的脚本 |
-s, --state | 显示该包中文件的状态(暗示 -l)。每个文件的状态是以下之一:normal, not installed, or replaced |
–triggers, --triggerscripts | 如果包中有的话,显示触发脚本 |
–noartifact | 不要显示 artifact 文件 |
–noconfig | 不要显示配置文件 |
–xml | 把包的头格式化为 XML |
示例:
# 查询指定的包是否已经安装
rpm -q tree
package tree is not installed
# 安装该包
rpm -ivh /path/to/tree
# 再次查询
rpm -q tree
tree-1.7.0-15.el8.x86_64
查询已经安装的包的信息 ( i for infomation)
rpm -qi tree
Name : tree
Version : 1.7.0
Release : 15.el8
Architecture: x86_64
Install Date: Wed 16 Nov 2022 03:48:35 PM CST
Group : Unspecified
Size : 111603
......
想要查询尚未安装包的信息,需要注意的是:此时需要完整路径,或 URL:
rpm -qpi /path/to/tree
查询该包安装后会生成那些文件,如果想知道未安装的包将会生成的文件列表 (-l for list),则增加 -p (for package)选项即可:
rpm -ql tree
/usr/bin/tree
/usr/lib/.build-id
/usr/lib/.build-id/d8
/usr/lib/.build-id/d8/6d516d7cb07fb9334cb268af808119e33a5ac5
/usr/share/doc/tree
/usr/share/doc/tree/LICENSE
/usr/share/doc/tree/README
/usr/share/man/man1/tree.1.gz
想要查询已经安装的命令来自于那个安装包,此时需要命令的完整路径 (-f for file):
rpm -qf `which tree`
tree-1.7.0-15.el8.x86_64
如果不小心删除了对应的命令,使用以上查询是可以的,因为rpm数据的内容还在。此时想要使用以下命令重新安装,会提示该包已经安装。
rpm -ivh /path/to/tree-1.7...
此时可以使用 --replacepkgs 或 --force 选项来重新安装
rpm -ivh --force /path/to/tree...
当然也可以把包中的对应文件提取出来,复制到对应的目录中。这种方法可以出现文件的属性与原来的不同:
rpm2cpio /path/to/tree... | cpio -idv ./tree
总结:使用rpm进行查询是非常有用的。主要的查询有:
-qi PACKAGE-NAME # 查看包的信息
-qf FILE # 查看那个包安装了这个文件
-qc PACKAGE-NAME # 查看包的配置文件
-ql PACKAGE-NAME # 列出安装包时生成的所有文件列表
-qd PACKAGE-NAME # 列出安装包时生成的所有文档列表
-q --scripts PACKAGE-NAME # 查询安装或卸载时的脚本
-qpi PACKAGE-NAME # 查询尚未安装的包的信息,名称要完整路径或URL
-qpl PACKAGE-NAME # 查询尚未安装的包会生成多少文件,名称要完整或URL
-qa # 查询所有已经安装的包
3.3 卸载
软件的卸载一般我们也不使用这个命令。如果我们要卸载的命令被其他软件依赖,卸载不能成功。
rpm 卸载命令的通用格式为:
rpm {-e|--erase} [--allmatches] [--justdb] [--nodeps] [--noscripts]
[--notriggers] [--test] PACKAGE-NAME...
3.4 校验
3.4.1 检查包的完整性和签名
rpm -K|--checksig rmpfile
示例:直接检查光盘自带的包:
cd /misc/cd/BaseOS/Packages
rpm -K bash-4.4.20-2.el8.x86_64.rpm
bash-4.4.20-2.el8.x86_64.rpm: digests SIGNATURES NOT OK
结果显示签名不ok。
其实我们需要使用系统已经安装的文件:
cd /etc/pki/rpm-gpg/
ll
total 8
-rw-r--r--. 1 root root 1683 Sep 15 2021 RPM-GPG-KEY-centosofficial
-rw-r--r--. 1 root root 1687 Sep 15 2021 RPM-GPG-KEY-centostesting
在检查包的来源和完整性之前,必须导入所需的公钥:
RPM-GPG-KEY-centosofficial 就是公钥文件。
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
rpm -K bash-4.4.20-2.el8.x86_64.rpm
bash-4.4.20-2.el8.x86_64.rpm: digests signatures OK
rpm -qa "gpg-pubkey*"
gpg-pubkey-8483c65d-5ccc5b19
3.4.2 rpm 校验命令的通用格式:
rpm {-v|--verify} [select-options] [verify-options]
校验一个包是通过比较包中已安装的文件的信息与来自保存在rpm数据库中的对应包的元数据中的文件信息。除此之外,验证会比较每个文件的大小、摘要、权限、类型、所有者和组。显示任何差异。
示例,用于检验文件是否修改过:
rpm -qf /etc/issue
centos-linux-release-8.5-1.2111.el8.noarch
# 对 issue 文件进行一些修改后
rpm -V centos-release
S.5....T. c /etc/issue
S 文件大小不同
M 模式不同
5 摘要不同
D 设备主/次编号不同
L 链接不同
U 用户不同
G 组不同
T mTime 不同
p capability 不同
使用以下选项可以查询所有不同的文件:
rpm -Va
3.5 rpm数据库
rpm 包在安装时生成的信息,都放在该数据库中:
/var/lib/rpm
可以使用以下命令重建数据库,其实这是创建了数据库的字段的创建,里面数据记录无法恢复:
rpm {--initdb|--rebuilddb}
initdb: 初始化,如果不存在,则创建它,否则,不执行任何操作
rebuilddb: 重建已安装的包头数据库索引目录