CentOS 软件包 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 包管理器相关文件
  1. 包文件组成(每个包独有)

    • 包内的文件
    • 元数据,例如,包名,版本,依赖,描述等
    • 可能有包安装或卸载时运行的脚本,例如可能需要创建运行的账号
  2. 数据库(公共):/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: 重建已安装的包头数据库索引目录
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值