如何轻松修复Fedora程序包
2012-04-12 01:00:00 Author: www.4hou.com(查看原文) 阅读量:45 收藏

xiaohui 技术 2020-02-16 10:30:00

收藏

Fedora 是一个 Linux 发行版,是一款由全球社区爱好者构建的面向日常应用的快速、稳定、强大的操作系统。 [1] 它允许任何人自由地使用、修改和重发布,无论现在还是将来。它由一个强大的社群开发,这个社群的成员以自己的不懈努力,提供并维护自由、开放源码的程序和开放的标准。

尽管许多Linux用户是开发人员,但相当一部分开发人员在使用时会经常干预或扩展已发行的程序包。当程序包中有待处理的功能,或者程序包中有漏洞时,用户通常会等待发行维护者对其进行修复,或者使用独立的解决方案(例如自制程序)来自行构建。

幸运的是,在Fedora中,开发人员可以处理每个程序包自身的问题,并使构建修改版本变得异常容易。

安装原始程序包

首先,我们从安装几个基本系统程序包开始,这些程序包将帮助我们处理程序包构建:

$ sudo dnf install fedpkg make

假设我们要考虑zsh(Z Shell)的补丁或功能,就需要考虑什么是生成二进制文件的源程序包项目。查询rpm工具很容易,根据已安装程序包的文件名,可以显示源程序包RPM的名称。例如:

$ rpm -qif /usr/bin/zsh | grep 'Source RPM'
Source RPM  : zsh-5.7.1-4.fc30.src.rpm

源RPM名称也是zsh,这并不奇怪。但是,其他包可能不是这样。

通常,源程序包的RPM名称与 Git存储库的名称相匹配,这意味着,Fedora在该Git存储库中维护允许构建它的脚本。从Fedora的Git服务器克隆源程序包非常容易,并且不需要成为Fedora社区成员或使用任何其他凭据。对于zsh,我们可以使用fedpkg执行以下命令:

$ fedpkg co -a zsh
Cloning into 'zsh'...
remote: Counting objects: 1023, done.
remote: Compressing objects: 100% (777/777), done.
remote: Total 1023 (delta 556), reused 423 (delta 216)
Receiving objects: 100% (1023/1023), 235.29 KiB | 271.00 KiB/s, done.
Resolving deltas: 100% (556/556), done.

对于每个程序包,每个版本的Fedora的源都保存在不同的分支中。因此,我们可以找出与我们要为其构建的发行版本匹配的分支:

$ cd zsh
$ git checkout -b f31 origin/f31
Branch 'f31' set up to track remote branch 'f31' from 'origin'.
Switched to a new branch 'f31'

从现在开始,我们将在程序包的工作目录中调用fedpkg。

设置构建环境

对于正常运行的开发环境,不同的程序包将有不同的要求。幸运的是,Fedora的dnf可以帮助我们引入它可以构建的任何程序包所需的依赖项。这可以通过dnf builddep命令来完成。对于我们的用例,我们可以引入zsh依赖项:

$ sudo dnf builddep zsh

直接建立可分配的RPM

在修改包之前,有必要测试一下,看看我们是否能够在不进行任何修改的情况下正确地构建它,以下命令将尝试从代码的当前状态构建二进制RPM:

$ fedpkg local

我们可以观察到已经生成了以下RPM:

$ ls -l1 x86_64/ noarch/
noarch/:
total 452
-rw-rw-r--. 1 user user 459748 Jan 14 13:58 zsh-html-5.7.1-4.fc31.noarch.rpm

x86_64/:
total 5476
-rw-rw-r--. 1 user user 2999294 Jan 14 13:58 zsh-5.7.1-4.fc31.x86_64.rpm
-rw-rw-r--. 1 user user 1771784 Jan 14 13:58 zsh-debuginfo-5.7.1-4.fc31.x86_64.rpm
-rw-rw-r--. 1 user user  829306 Jan 14 13:58 zsh-debugsource-5.7.1-4.fc31.x86_64.rpm

或者,在模拟容器中构建RPM。

甚至在Docker容器流行之前,Fedora就向我们提供了一个名为mock的工具,该工具会创建了一个用于构建程序包的独立环境。因此,可以使用它独立于开发环境来构建程序包。

首先,我们需要确保安装了mock。

$ sudo dnf install mock

然后,我们可以告诉fedpkg使用mock来构建包:

$ fedpkg mockbuild

mock的构建输出全部被移动到一个目录,其中包含构建的日志文件以及程序包的版本和名称:

$ ls -lR results_zsh/*/*
results_zsh/5.7.1/4.fc31:
total 9852
-rw-rw-r--. 1 user user  190779 Jan 14 14:10 build.log
-rw-rw-r--. 1 user user    2744 Jan 14 14:03 hw_info.log
-rw-rw-r--. 1 user user   52642 Jan 14 14:08 installed_pkgs.log
-rw-rw-r--. 1 user user  614047 Jan 14 14:10 root.log
-rw-rw-r--. 1 user user     998 Jan 14 14:10 state.log
-rw-r--r--. 1 user mock 3146067 Jan 14 14:06 zsh-5.7.1-4.fc31.src.rpm
-rw-r--r--. 1 user mock 2999346 Jan 14 14:10 zsh-5.7.1-4.fc31.x86_64.rpm
-rw-r--r--. 1 user mock 1772488 Jan 14 14:10 zsh-debuginfo-5.7.1-4.fc31.x86_64.rpm
-rw-r--r--. 1 user mock  829174 Jan 14 14:10 zsh-debugsource-5.7.1-4.fc31.x86_64.rpm
-rw-r--r--. 1 user mock  459682 Jan 14 14:10 zsh-html-5.7.1-4.fc31.noarch.rpm

使用mock执行构建的优势在于,它可以验证构建的依赖项是否正确指定,并且还可以用于在同一台计算机上针对发行版的不同版本进行构建。另外,它也是Fedora自己的构建服务器(即Copr)背后的运行设备。

添加补丁

要为程序包生成补丁,我们需要包本身的源代码,而不是告诉我们如何构建它的Fedora脚本的源代码。

有多种获取源代码的方法,其中一种是使用fedpkg。我们可以让它创建一个目录,其中包含已准备好构建的修补程序包源代码。这个过程将执行RPM规范源代码的准备阶段,结果通常是工作树下的一个目录。

$ fedpkg prep

因为Fedora源代码包不会考虑源代码控制方面的问题,所以它们只包含某个版本源代码的压缩文件。在源代码控制中不跟踪创建的目录,如果要修改它,通常最好将它移到另一个目录,并使用Git对其进行初始化。如下所示:

$ mv zsh-5.7.1 ../zsh-5.7.1
$ cd ../zsh-5.7.1
$ git init && git add -f . && git commit -m "Base version"

在这个示例中,我们的zsh-5.7.1只是该Fedora维护版本的代表,它可能已经被Fedora进行了某种程度的修补,但是它可以并且应该被用作我们进一步修补的基础。但是,我们可能想要克隆完整的项目,在这种情况下,zsh方便于完整的Git历史浏览。

$ cd ..
$ git clone git://git.code.sf.net/p/zsh/code zsh-upstream
Cloning into 'zsh-upstream'...
remote: Enumerating objects: 94026, done.
remote: Counting objects: 100% (94026/94026), done.
remote: Compressing objects: 100% (25128/25128), done.
remote: Total 94026 (delta 73505), reused 87930 (delta 68487)
Receiving objects: 100% (94026/94026), 16.60 MiB | 1.07 MiB/s, done.
Resolving deltas: 100% (73505/73505), done.

回到任何一个源代码克隆,我们都可以继续提交更改并通过提交生成补丁,以下就是一个简单补丁的示例:

$ git diff HEAD
diff --git a/Src/hist.c b/Src/hist.c
index dbdc1e4..cdb1dd1 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -580,7 +580,7 @@ histsubchar(int c)
      */
     lexraw_mark = zshlex_raw_mark(-1);-    /* look, no goto's */+    /* look, no goto's! */     if (isfirstch && c == hatchar) {
        int gbal = 0;

$ git commit -m "Adding an exclamation mark to Src/hist.c"
[f31 c00d68b] Adding an exclamation mark to Src/hist.c
 2 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 0001-zsh-5.7.1-zle-history-avoid-crash.patch

$ git format-patch HEAD~1 -o ../zsh
../zsh/0001-Adding-an-exclamation-mark-to-Src-hist.c.patch

git format-patch是一个方便的命令,可以将git提交为文件,它的输出可以作为程序包构建过程的输入,因为Fedora中的程序包标准要求其上层的源代码与在其上生成的补丁分开。

将补丁文件添加到Fedora程序包的源规范中可能会有些棘手,但是经过几次之后,你了解到打包格式比起初看起来更简单。对于zsh,我们只需要在zsh.spec开头的Patch

$ git diff
diff --git a/zsh.spec b/zsh.spec
index 0d77f70..0022a90 100644
--- a/zsh.spec
+++ b/zsh.spec
@@ -14,6 +14,7 @@ Source6: dotzshrc

 # make failed searches of history in Zle robust (#1722703)
 Patch1:  0001-zsh-5.7.1-zle-history-avoid-crash.patch+Patch2:  0001-Adding-an-exclamation-mark-to-Src-hist.c.patch
 BuildRequires: autoconf
 BuildRequires: coreutils

较旧的程序包可能需要更多更改,例如,在文件中进一步添加与上述准备阶段有关的额外%patch行。

识别修补过的程序包

如果没有其他的.spec字段被更改,我们修改后的包在元数据中与原始包几乎没有区别。通常情况下这是不需要的。因此,最好将.spec修改为在程序包的Release字段中包含一个字符串。例如:

diff --git a/zsh.spec b/zsh.spec
index 0022a90..78c362e 100644
--- a/zsh.spec
+++ b/zsh.spec
@@ -1,7 +1,7 @@
 Summary: Powerful interactive shell
 Name: zsh
 Version: 5.7.1-Release: 4%{?dist}+Release: 4%{?dist}.daloni License: MIT
 URL: http://zsh.sourceforge.net/
 Source0: https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.xz

我们可以看到,在构建之后。

$ ls -l1 x86_64/ noarch/

noarch/:
total 452
-rw-rw-r--. 1 user user 459790 Jan 14 15:15 zsh-html-5.7.1-4.fc31.daloni.noarch.rpm

x86_64/:
total 5476
-rw-rw-r--. 1 user user 2999482 Jan 14 15:15 zsh-5.7.1-4.fc31.daloni.x86_64.rpm
-rw-rw-r--. 1 user user 1773094 Jan 14 15:15 zsh-debuginfo-5.7.1-4.fc31.daloni.x86_64.rpm
-rw-rw-r--. 1 user user  829124 Jan 14 15:15 zsh-debugsource-5.7.1-4.fc31.daloni.x86_64.rpm

安装程序包

可以通过dnf install安装新程序包,一旦安装了修补程序包,就可以通过各种方式安装的dnf list的输出进行重复查找,从而轻松发现它们。

$ sudo dnf install x86_64/zsh-5.7.1-4.fc31.daloni.x86_64.rpm

$ dnf list installed | grep @@commandline
zsh.x86_64              5.7.1-4.fc31.daloni                    @@commandline

$ dnf list installed | grep daloni
zsh.x86_64              5.7.1-4.fc31.daloni                    @@commandline

避免补丁在版本升级时被覆盖

当Fedora发布新版本的程序包时,自动系统升级可能会覆盖补丁。虽然有几种方法可以防止这个情况的发生,但我最喜欢的一种方法是从dnf的配置中排除对此类程序包的升级。

$ grep exclude /etc/dnf/dnf.conf
exclude=zsh

不过,处理程序包的话题已经超出了本文的范围。

保留debuginfo!

如果修补的程序包崩溃并生成了一个核心文件,那么构建中生成的特殊的debuginfo程序包在检查这个corefile时可能很方便。因此,你可能需要保留这些debuginfo程序包,特别是因为复制的构建有时很难与原始的二进制兼容性完全匹配。这取决于构建包的确定性如何,这是程序包自身构建系统固有的问题。

本文翻译自:https://blog.aloni.org/posts/how-to-easily-patch-fedora-packages/如若转载,请注明原文地址:


文章来源: https://www.4hou.com/posts/O5jQ
如有侵权请联系:admin#unsafe.sh