科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航



ZDNet>网络频道>ZD评测>如何给类unix操作系统打补丁

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

如果你现在还不懂得如何给类unix操作系统打补丁,那没有关系,我们就一起来试试,因为在刚开始写这篇文章的时候,我也不会给自己的程序打补丁。

来源: 2007年10月18日

关键字:补丁文件 控制字符 符号标识 APIC unix 补丁

  类unix操作系统有一个很有趣的特性就是源代码级的补丁包。在windows上我们打补丁都是运行一个可执行的程序,然后就可以把补丁打完了,这对于最终用户是非常方便的,但是对我们这些求知欲比较强的Linux fans来说就有点不过瘾了,因为我们不知道里面是怎么做的。而Linux的补丁就有趣多了,我们首先获得程序的源代码和对应的补丁文件,然后给源代码打补丁,产生新的源代码文件。然后再编译这个新的源代码文件,就获得了打过补丁的新程序了。

  解释patch文件

  我们可以使用diff命令加参数-ruN来比较两个文件并生成一个补丁文件。这个补丁文件会列出这两个不同版本文件的差异来。我们将通过一个特定例子来解释这个由diff命令生成的补丁文件(patch file)。

  假定:我们对检查linux-2.2.13和linux-2.2.14这两个不同的版本的差别很感兴趣。

  第一步,我们使用如下命令:

  make distclean

  这样可以在两个源代码目录中删去所有非文本文件。

  然后我们继续第二步:

  *****************************************************************************

  diff -ruN linux-2.2.13 linux-2.2.14 >/tmp/patch-2.2.14

  *****************************************************************************

  COMMAND EXECUTION:

  -r 是一个递归选项,设置了这个选项,diff会将两个不同版本源代码目录中的所有对应文件全部都进行一次比较,正如你所料,这种比较也是包括子目录中的文件的。

  -N 选项表明如果一个文件存在于一个目录中,那么它就必须被认为是在这个目录中的,哪怕这个文件在对应的目录中是一个空文件。(举个例子,如果在老版本中有这么一个文件,但是在新版本中这个文件被去掉了,那么diff仍然会把它记录下来,我们打完补丁以后,在得到的新版本代码中,老版本的那个文件名仍然会存在,但是是一个空文件)

  -u 选项指明正在使用的是统一的输出格式。

  下面我们查看一下经过重定向后生成的补丁文件/tmp/patch-2.2.14,下面是我们从该文件中摘抄的一部分补丁信息:

  *****************************************************************************

  diff -ruN linux-2.2.13/arch/i386/kernel/signal.c

  linux-2.2.14/arch/i386/kernel/signal.c

  这里第一个版本的名字,linux-2.2.13是参考版本(就是旧版本),所有的在linux-2.2.14(新版本)中发现的问题都是和第一个版本相关的。

  *****************************************************************************

  DIFF HEADER:

  diff命令会在补丁文件中记录这两个文件的首次创建时间,如下:

  *****************************************************************************

  *** linux-2.2.13/arch/i386/kernel/signal.c Tue Jun 8 01:14:20 1999

  --- linux-2.2.14/arch/i386/kernel/signal.c Sun Jan 23 17:29:25 2000

  *****************************************************************************

  DIFF BODY:

  diff 命令在这两个文件之间发现了3类差异。

  a) 添加(addition):

  这一行在旧版本的文件中没有,但是被添加到了新版本的文件中。

  b) 置换(replacement):

  在新版本文件中用连续的几行替换掉了旧版本文件中连续的几行。

  c) 删除(deletion):

  在旧版本文件中的一行在新版本文件中不再出现。

  在每一种情况下,发生变化的行号都会被提示出来。

  让我们解释一下diff用来指明这三种情况时使用的符号:

  *****************************************************************************

  添加(ADDITION):

  看补丁文件中如下的行: (相对于arch/i386/kernel/signal.c文件的新旧两个版本)

  *** 419,431 ****

  --- 419,437 ----

  ? current->exec_domain->signal_invmap[sig]

  : sig),

  &frame->sig);

  + if (err)

  + goto give_sigsegv;

  使用+号指明在“&frame->sig);”这一行后面要加两个新行。这两个新行就是用+符号开头的两行。

  *** 419,431 ****向读者指明可以从旧文件的419行到431行来查阅这些变化;同样的,--- 419,437 ----向读者指明可以从新文件的419到437行来查阅这些变化。这样一来,新旧一比较,就可以知道哪些地方发生了什么变化。

  不过在新版本的diff中,似乎并不是用这种方法来表明新旧文件对应的行号的,而使用@这个符号,对应于上例中的:

  *** 419,431 ****

  --- 419,437 ----

  我们看到的新的标识可能是:

  @@ -419,431 +419,437 @@

  对于这种表示方法,我还不是很懂,如果有哪位朋友比较懂的话,非常欢迎你将这部分内容加进来。

  不过,有一点需要说明一下,就是这个行号并不是完全必需的,其实这个行号在给源代码打补丁的时候是没有用的,这里提示出来主要是给开发人员比较分析时使用的。

  置换(REPLACEMENT):

  看补丁文件中如下的行: (相对于arch/i386/kernel/signal.c文件的新旧两个版本)

  ***************

  *** 367,377 ****

  printk("I/O APIC #%d Version %d at 0x%lX.\n",

  m->mpc_apicid,m->mpc_apicver,

  m->mpc_apicaddr);

  ! /*

  ! * we use the first one only currently

  ! */

  ! if (ioapics == 1)

  ! mp_ioapic_addr = m->mpc_apicaddr;

  }

  mpt+=sizeof(*m);

  count+=sizeof(*m);

  然后后面又紧跟着如下的行:

  --- 368,376 ----

  printk("I/O APIC #%d Version %d at 0x%lX.\n",

  m->mpc_apicid,m->mpc_apicver,

  m->mpc_apicaddr);

  ! mp_apics [mp_apic_entries] = *m;

  ! if (++mp_apic_entries >MAX_IO_APICS)

  ! --mp_apic_entries;

  }

  mpt+=sizeof(*m);

  count+=sizeof(*m);

  这里就指明了在旧版本文件中用!符号标识的5行被在新版本文件中用!标识的3行替换了。

  由此可见,符号!就意味着替换。但是为什么会有替换,而不是先删除再添加,这里我就不清楚了。还是得请知道的朋友指点一下了。

  删除(DELETION):

  看补丁文件中如下的行: (相对于drivers/net/Config.in文件的新旧两个版本)

  ***************

  *** 93,100 ****

  fi

  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then

  tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139

  - tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900

  - tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN

  fi

  bool 'Other ISA cards' CONFIG_NET_ISA

  if [ "$CONFIG_NET_ISA" = "y" ]; then

  --- 94,99 ----

  ***************

  在旧版本文件中用-符号标识的两行说明这两行在新版本的文件中不会再出现了,也就是说,在新版本的文件中,这两行被删除了。

  建立一个自己的补丁

  你现在修改并测试了一个新的Linux版本,就称它为Linux-2.4.5kh3,这个版本和你当前使用的称作Linux-2.4.5kh2的“老”版本有一些些不同。

  现在你想制作一个可以将Linux-2.4.5kh2升级到Linux-2.4.5kh3的补丁程序。顺便多说句废话,理所当然的这个补丁程序要比Linux内核的源代码小的多。

  这个补丁文件一般使用一张软盘就可以装下来,因此这对于升级另一台计算机上的旧的操作系统内核是非常有用的。

  本质上制作补丁程序只有两个步骤,如下描述:

  a) 在计算机A上产生一个补丁文件(计算机A就是那台既有新内核的源代码又有老内核的源代码的计算机)。并且将这个补丁文件复制到一张软盘上。

  b) 在计算机B上读取保存有补丁文件的软盘,并利用补丁文件将计算机B上的旧内核升级为新的内核。

  下面我们进行详细的说明。其中第1到第4步描述了怎样制作一个补丁文件,并把它复制到软盘上。第5到第6步描述了怎么样使用补丁文件将旧的操作系统内核升级到新的版本。

  *****************************************************************************

  第1步:清理两个内核的源代码文件(没有*.o的文件或者.*文件)

  *****************************************************************************

  我们假定这两个内核的源代码路径分别是:

  /usr/src/linux-2.4.5kh2和/usr/src/linux-2.4.5kh3

  运行如下命令:

  cd /usr/src/linux-2.4.5kh2

  make distclean

  cd /usr/src/linux-2.4.5kh3

  make distclean

  *****************************************************************************

  第2步:在两个内核源代码版本之间产生一个“context diffs”文件(这个文件指明了两个不同版本源代码之间的所有不同)。

  *****************************************************************************

  运行如下命令(首先是旧的内核,然后是新的内核):

  cd /usr/src

  diff -ruN linux-2.4.5kh2 linux-2.4.5kh3 >patch-2.4.5kh3

  *****************************************************************************

  第3步:检查补丁文件。

  *****************************************************************************

  运行如下命令查看补丁文件以确定它没有包含任何的垃圾:

  less patch-2.4.5kh3

  这里所说的垃圾就是非ASCI码的乱码,或控制字符。如果发现补丁文件中存在着不是文本的内容,那就是有垃圾了。这是我们需要重新操作第1至第3步

  *****************************************************************************

  第4步:将补丁文件复制到一张软盘上。

  *****************************************************************************

  mount /flp

  cp /usr/src/patch-2.4.5kh3 /flp

  umount /flp

  由于我们的补丁文件一般都很小,所以我们不需要压缩它。现在我们拿着这张带有补丁程序的软盘转移到计算机B前面去。

  *****************************************************************************

  第5步:从软盘中读取补丁文件。

  *****************************************************************************

  cd /usr/src

  mount /flp

  cp /flp/patch-2.4.5kh3 patch-2.4.5kh3

  umount /flp

  *****************************************************************************

  第6步:使用这个补丁文件将旧内核的源代码升级到新内核的版本。

  *****************************************************************************

  a) 执行奇妙的patch命令:

  patch -p0

  patch命令作用在输入的补丁文件patch-2.4.5kh3上,并将对应的老版本的内核源代码中所有的文件和子目录升级到对应的新版本(当然这里的老版本一定要和我们在计算机A上运行diff命令时的那个老版本是一样的)。在我们的例子中,旧的内核源代码版本是Linux-2.4.5kh2。这里参数–p0用来保证文件名不被改变(既不被修改,也不被删除)。

  b) 重新命名内核源代码:

  mv linux-2.4.5kh2 linux-2.4.5kh3

推广二维码
邮件订阅

如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

重磅专题