rpm 系 linux 系统中 repo 文件中的 $release 到底等于多少?

结论

对于 8 来说,通过以下命令

#/usr/libexec/platform-python -c 'import dnf, json; db = dnf.dnf.Base(); print(json.dumps(db.conf.substitutions, indent=2))'
{
"arch": "x86_64",
"basearch": "x86_64",
"releasever": "8"
}

对于 7 来说,通过以下命令

#python -c 'import yum, json; yb = yum.YumBase(); print json.dumps(yb.conf.yumvar, indent=2)'

或者通过以下命令获取 releasever 的值,repo 为 @system 代表当前系统安装的包。

#yum provides system-release\(releasever\)
anolis-release-8.2-15.an8.x86_64 : Anolis OS 8 release file
Repo : @System
Matched from:
Provide : system-release(releasever) = 8 anolis-release-8.2-15.an8.x86_64 : Anolis OS 8 release file
Repo : BaseOS
Matched from:
Provide : system-release(releasever) = 8

例子:

以下取自 stackover

# CentOS 8:
# ---
[root@0928d3917e32 /]# /usr/libexec/platform-python -c 'import dnf, json; db = dnf.dnf.Base(); print(json.dumps(db.conf.substitutions, indent=2))'
Failed to set locale, defaulting to C
{
"arch": "x86_64",
"basearch": "x86_64",
"releasever": "8"
}
[root@0928d3917e32 /]# # CentOS 7:
# ---
[root@c41adb7f40c2 /]# python -c 'import yum, json; yb = yum.YumBase(); print json.dumps(yb.conf.yumvar, indent=2)'
Loaded plugins: fastestmirror, ovl
{
"uuid": "cb5f5f60-d45c-4270-8c36-a4e64d2dece4",
"contentdir": "centos",
"basearch": "x86_64",
"infra": "container",
"releasever": "7",
"arch": "ia32e"
}
[root@c41adb7f40c2 /]# # CentOS 6:
# ---
[root@bfd11c9a0880 /]# python -c 'import yum, json; yb = yum.YumBase(); print json.dumps(yb.conf.yumvar, indent=2)'
Loaded plugins: fastestmirror, ovl
{
"releasever": "6",
"basearch": "x86_64",
"arch": "ia32e",
"uuid": "3e0273f1-f5b6-481b-987c-b5f21dde4310",
"infra": "container"
}
[root@bfd11c9a0880 /]#

原理

以 8 为例

/usr/libexec/platform-python -c 'import dnf, json; db = dnf.dnf.Base(); print(json.dumps(db.conf.substitutions, indent=2))'

{
"arch": "x86_64",
"basearch": "x86_64",
"releasever": "8"
}

主要是以下几行代码

import dnf, json
db = dnf.dnf.Base()
print(json.dumps(db.conf.substitutions, indent=2))

然后对源码进行粗略的分析

# /usr/lib/python3.6/site-packages/dnf/base.py
class Base(object): def __init__(self, conf=None):
# :api
self._closed = False
self._conf = conf or self._setup_default_conf()
self._goal = None
# ...
@staticmethod
def _setup_default_conf():
conf = dnf.conf.Conf()
subst = conf.substitutions
if 'releasever' not in subst:
subst['releasever'] = \
dnf.rpm.detect_releasever(conf.installroot)
return conf

主要是这行代码

subst['releasever'] = \
dnf.rpm.detect_releasever(conf.installroot)

首先 subst 是从 os.environ.items() varsdir=("/etc/yum/vars/", "/etc/dnf/vars/") 得来的,如果 releasever 这个变量不在 subset 里面,他就会去执行下面的代码 dnf.rpm.detect_releasever(conf.installroot)

这个函数我在下面也贴出来了,它是会遍历以下元组,作为 distroverpkg 的值,通过该函数 ts.dbMatch('provides', distroverpkg) 去获取对应值并提取 ,个人感觉这个类似于 yum provides 这个命令,然后他是按照顺序搞的,所以如果第一个值能获得 $releasever ,就选用该值。

DISTROVERPKG=('system-release(releasever)', 'system-release',
'distribution-release(releasever)', 'distribution-release',
'redhat-release', 'suse-release', 'anolis-release')

在我系统上测试,发现第一个 system-release(releasever) 就可以匹配到该值了,所以此时 $releasever 的值就是该值。

# yum provides system-release\(releasever\)
anolis-release-8.2-15.an8.x86_64 : Anolis OS 8 release file
Repo : @System
Matched from:
Provide : system-release(releasever) = 8 anolis-release-8.2-15.an8.x86_64 : Anolis OS 8 release file
Repo : BaseOS
Matched from:
Provide : system-release(releasever) = 8

以下是部分源码及路径

#/usr/lib/python3.6/site-packages/dnf/conf/__init__.py
from dnf.conf.config import BaseConfig, MainConf, RepoConf Conf = MainConf
#/usr/lib/python3.6/site-packages/dnf/conf/config.py
class MainConf(BaseConfig):
# :api
"""Configuration option definitions for dnf.conf's [main] section."""
def __init__(self, section='main', parser=None):
self.substitutions = dnf.conf.substitutions.Substitutions() #/usr/lib/python3.6/site-packages/dnf/conf/substitutions.py
class Substitutions(dict):
# :api def __init__(self):
super(Substitutions, self).__init__()
self._update_from_env() def _update_from_env(self):
numericvars = ['DNF%d' % num for num in range(0, 10)]
for key, val in os.environ.items():
if ENVIRONMENT_VARS_RE.match(key):
self[key[8:]] = val # remove "DNF_VAR_" prefix
elif key in numericvars:
self[key] = val def update_from_etc(self, installroot, varsdir=("/etc/yum/vars/", "/etc/dnf/vars/")):
# :api for vars_path in varsdir:
fsvars = []
try:
dir_fsvars = os.path.join(installroot, vars_path.lstrip('/'))
fsvars = os.listdir(dir_fsvars)
except OSError:
continue
for fsvar in fsvars:
filepath = os.path.join(dir_fsvars, fsvar)
if os.path.isfile(filepath):
try:
with open(filepath) as fp:
val = fp.readline()
if val and val[-1] == '\n':
val = val[:-1]
except (OSError, IOError):
continue
self[fsvar] = val
# /usr/lib/python3.6/site-packages/dnf/rpm/__init__.py
def detect_releasever(installroot):
# :api
"""Calculate the release version for the system.""" ts = transaction.initReadOnlyTransaction(root=installroot)
ts.pushVSFlags(~(rpm._RPMVSF_NOSIGNATURES | rpm._RPMVSF_NODIGESTS))
for distroverpkg in dnf.const.DISTROVERPKG:
if dnf.pycomp.PY3:
distroverpkg = bytes(distroverpkg, 'utf-8')
try:
idx = ts.dbMatch('provides', distroverpkg)
except (TypeError, rpm.error) as e:
raise dnf.exceptions.Error('Error: %s' % str(e))
if not len(idx):
continue
try:
hdr = next(idx)
except StopIteration:
msg = 'Error: rpmdb failed to list provides. Try: rpm --rebuilddb'
raise dnf.exceptions.Error(msg)
releasever = hdr['version']
try:
try:
# header returns bytes -> look for bytes
# it may fail because rpm returns a decoded string since 10 Apr 2019
off = hdr[rpm.RPMTAG_PROVIDENAME].index(distroverpkg)
except ValueError:
# header returns a string -> look for a string
off = hdr[rpm.RPMTAG_PROVIDENAME].index(distroverpkg.decode("utf8"))
flag = hdr[rpm.RPMTAG_PROVIDEFLAGS][off]
ver = hdr[rpm.RPMTAG_PROVIDEVERSION][off]
if flag == rpm.RPMSENSE_EQUAL and ver:
if hdr['name'] not in (distroverpkg, distroverpkg.decode("utf8")):
# override the package version
releasever = ver
except (ValueError, KeyError, IndexError):
pass
# /usr/lib/python3.6/site-packages/dnf/const.py
DISTROVERPKG=('system-release(releasever)', 'system-release',
'distribution-release(releasever)', 'distribution-release',
'redhat-release', 'suse-release', 'anolis-release')

原理证明

既然经过一番探索,自然得验证下,以下以 Anolis OS 8 系统为例子。

anolis-release 这个包的代码分析。源码路径

anolis-release.spec 文件中可以看到,这个包会提供 system-release(releasever) = %{base_release_version}

%{base_release_version} 在文件定义中是 8,从 koji 的构建记录也可以看出,确实会产出 system-release(releasever) = 8

%define anolis_release 15

%define debug_package %{nil}
%define product_family Anolis OS
%define base_release_version 8
%define full_release_version 8.2
%define compat_release_version 8
%define beta Beta
%define dist .an%{base_release_version} Name: anolis-release
Version: %{full_release_version}
Release: %{anolis_release}%{?dist}
Summary: %{product_family} %{base_release_version} release file
Group: System Environment/Base
License: MulanPSLv2
Obsoletes: rawhide-release redhat-release-as redhat-release-es redhat-release-ws redhat-release-de comps rpmdb-redhat fedora-release redhat-release centos-release
Provides: redhat-release = %{full_release_version}
Provides: centos-release = %{full_release_version}
Provides: system-release = %{version}-%{release}
Provides: system-release(releasever) = %{base_release_version}

该包在 koji 上的构建记录 http://8.131.87.1/koji/rpminfo?rpmID=66924

Provides
anolis-release = 8.2-13.an8
anolis-release(x86-64) = 8.2-13.an8
centos-release = 8.2
config(anolis-release) = 8.2-13.an8
redhat-release = 8.2
system-release = 8.2-13.an8
system-release(releasever) = 8

结论

然后,这个 system-release(releasever) 并不会像 os-release 一样写进系统文件里(/etc/os-release),但是确实会在系统中 provides ,而 $releasever 会按照元组中定义的顺序选取值,最终选到了该值。

反推

既然这样我是不是可以修改这个值,让系统的 $releasever 显示别的值,答案是可以的。

我通过修改 spec 文件中的变量为 %define base_release_version 7

然后通过 mock 重新构建该包,安装到我的系统上,成功让 $releasever 这个变量变成了我想要的值 ( 如下 ),当然此时 yum 源可能会有问题,你可能需要修改 .repo文件中 $releasever 为原来的值,再次下载 yum 源里的 anolis-release 这个包,就可以恢复原来的值了。

# yum provides system-release\(releasever\)
Failed to set locale, defaulting to C.UTF-8
Repository AppStream is listed more than once in the configuration
Repository BaseOS is listed more than once in the configuration
Repository Plus is listed more than once in the configuration
Repository PowerTools is listed more than once in the configuration
Last metadata expiration check: 0:01:02 ago on Sat Jun 18 10:42:33 2022.
anolis-release-8.2-14.an8.x86_64 : Anolis OS 8 release file
Repo : @System
Matched from:
Provide : system-release(releasever) = 7

mock 构建命令如下

rpmbuild -bs ~/rpmbuild/SPECS/*.spec --define "dist ${dist}"
mock -r xx.cfg clean
mock -r xx.cfg init
mock -r xx.cfg rebuild xx.src.rpm

通过 rpm -Uvh 安装构建出的 rpm 包

结语

想搞懂这个一个是对这方面比较好奇,而网上有很多误导,比如网上很多说是看 /etc/os-release 的值,所以想自己去找找真实的答案;另一方面工作中遇到了这方面的问题,故某天熬到2点多,仔细探查了一番。

有可能,我的分析也不对,大家参考就行。️

rpm 系 linux 系统中 repo 文件中的 $release 到底等于多少?的更多相关文章

  1. Linux系统下 MYSQL数据库中的数据库文件在本机内迁移 (需暂停服务的方式)

    Linux系统下 MYSQL数据库中的数据库文件在本机内迁移 本机采用Ubuntu16.04系统,tar方式安装MySQL5.7.21 数据库安装文件夹为    /home/devil/mysql 现 ...

  2. Linux显示检查设置文件中的语法是否正确

    Linux显示检查设置文件中的语法是否正确 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ apachectl [conflgtest] 程序"apa ...

  3. 使用Xshell在Windows系统和Linux系统之间进行文件传输

    版权声明:本文为转载内容. 原博客内容https://blog.csdn.net/love666666shen/article/details/75742077 Windows系统在安装虚拟机cent ...

  4. 查看Linux下*.a库文件中文件、函数、变量

    查看Linux下*.a库文件中文件.函数.变量等情况在Linux 下经常需要链接一些 *.a的库文件,那怎么查看这些*.a 中包 含哪些文件.函数.变量: 1. 查看文件:ar -t xxx.a 2. ...

  5. linux系统下修改文件夹目录权限

    linux系统下修改文件夹目录权限 文件夹权限问题 Linux.Fedora.Ubuntu修改文件.文件夹权限的方法差不多.很多人开始接触Linux时都很头痛Linux的文件权限问题.这里告诉大家如何 ...

  6. linux 系统获得当前文件夹下存在的所有文件 scandir函数和struct dirent **namelist结构体[转]

    linux 系统获得当前文件夹下存在的所有文件 scandir函数和struct dirent **namelist结构体 1.引用头文件#include<dirent.h> struct ...

  7. 使用WinSCP在Windows和Linux系统之间传输文件

    小梅哥编写,未经许可,严禁用于任何商业用途 2018年6月30日 在日常SoC开发中,我们经常需要在Windows和Linux系统之间传输文件,例如在Windows系统上的DS-5集成开发环境中编写好 ...

  8. linux系统加快大文件的写入速度

    linux系统加快大文件的写入速度 setvbuf进行优化内存IO

  9. Linux系统下查找文件的方法

    Linux系统下查找文件的方法 作者:Vashon 时间:20150419 方法一.在当前目录里查找所有名为以 java 开头的文件: find ./ -name "java*" ...

随机推荐

  1. Spring集成web环境(使用封装好的工具)

    接上文spring集成web环境(手动实现) ##########代码接上文############# spring提供了一个监听器ContextLoaderListener对上述功能的封装,该监听器 ...

  2. kubectl scale sts

    使用scale 不单单是扩容还可以:1.动态扩展服务,增加承载能力2.如果出现pod异常,可以利用这种方式,增加pod,再删除原来的pod 比如:pod所在宿主机网络或者宿主机死掉注: 但是一旦有某个 ...

  3. 关于croptool无法裁剪分辩率过低的图片

    在使用croptool.js时,如果图片的分辨率过低,则无法裁剪超过分辨率的大小.比如说 function chooseImg(event){ var files = event.files || e ...

  4. B. Build the Permutation

    题目分析:我们先简单的分析一下这道题是在干什么啊,给我们三个整数n,a,b,问我们能否构造这样的排列使得序列中有a个极大值,b个极小值,能的话就给出任意一种可能的情况,不能的话就输出-1: 其实一开始 ...

  5. Blazor 生命周期

    执行周期 1. SetParametersAsync 2. OnInitializedAsync(调用两次) 和 OnInitialized: 3. OnParametersSetAsync 或 On ...

  6. [.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢?

    [.NET Core]ASP.NET Core中如何解决接收表单时的不支持的媒体类型(HTTP 415 Unsupported Media Type)错误呢? 在ASP.NET Core应用程序中,接 ...

  7. baiyang网站二代域名及短链接

    http://985.so/wesv https://cloud.tencent.com/developer/column/93900

  8. python学习-Day26

    目录 今日内容详细 编程思想 面向过程编程 面向对象编程 类与对象 概念 类与对象的创建 先定义类 后产生对象 语法结构 如何产生对象 对象的实例化 绑定方法 今日内容详细 编程思想 面向过程编程 将 ...

  9. 利用VTK和PyQt5对医学体数据进行渲染并展示

    简介 在一些医学相关的简单的项目(也许是学生的作业?毕业设计?)中,有时候可能需要集成一些可视化的功能,本文简单介绍一下,如何利用PyQt5和VTK来渲染体数据(三维数据),并集成进PyQt的UI框架 ...

  10. 148_赠送300家门店260亿销售额的零售企业Power BI实战示例数据

    焦棚子的文章目录 一背景 2022年即将到来之际,笔者准备在Power BI中做一个实战专题,作为实战专题最基础的就是demo数据,于是我们赠送大家一个300家门店,260亿+销售额,360万行+的零 ...