做为一个Debian系统管理员,你将会经常接触.deb包,因为它们有助于安装软件和维护软件。因此好好了解.deb是很有帮助的。
本章描述了二进制包和源码包的组成。前者是指.deb包,直接使用dpkg,后者包含了源码,以及编译构建的指令。
5.1 .deb的结构
Debian包格式的设计要点之一是能够方便地使用ar,tar和gzip等命令提取文件。这样的设计看起来没有什么用途,但在移植性和灾难恢复等方面是非常重要的。
设想你误删了dpkg程序,因此你不能再安装Debian程序了。幸运的是,你了解包的格式,因此你可以下载dpkg包并手动安装。如果更加不幸地,连ar,tar或gzip/xz/bzip2也不存在,那你只需要去其他地方拷贝一份这些程序即可(因为这些程序不依赖其他任何程序)。
dpkg,APT,ar
dpkg程序操作.deb文件,特别是提取,分析和解包操作。
APT是一组程序:能够安装,移除一个软件包,更新系统,列出所有可有的包等。
对于ar程序,它能够对名称不变的多个文件进行操作:ar t显示了当前archive中包含的文件,ar x会将archive中的文件提取到当前工作目录,ar d删除当中的某个文件。ar的man手册中有详细描述。ar是一个很初级的程序,系统管理员很少会用到它,相反,管理员们会经常使用tar工具来作为文件管理程序。这就是为什么在误删dpkg后很容易恢复它的原因。你仅仅需要下载包,并从.tar.gz中提取文件:
# ar x dpkg_1.16.10_amd64.deb
# tar -C / -p -xzf data.tar.gz
man表示法
对于初学者,可能不理解“ar(1)”的意义,它的意思是ar命令位于man的section 1中。
有时这种表示法也可以被用来区分同一个被检索对象的不同含义,例如,对于printf,printf(1)指的是printf工具,而printf(3)指的是c的库函数。
查看一个.deb文件的内容:
debian-binary
control.tar.gz
data.tar.gz
$ ar x dpkg_1.16.10_i386.deb
$ ls
control.tar.gz data.tar.gz ebian-binary dpkg_1.16.10_i386.deb
$ tar tzf data.tar.gz | head -n 15
./
./var/
./var/lib/
./var/lib/dpkg/
./var/lib/dpkg/updates/
./var/lib/dpkg/alternatives/
./var/lib/dpkg/info/
./var/lib/dpkg/parts/
./usr/
./usr/share/
./usr/share/locale/
./usr/share/locale/sv/
./usr/share/locale/sv/LC_MESSAGES/
./usr/share/locale/sv/LC_MESSAGES/dpkg.mo
./usr/share/locale/it/
$ tar tzf control.tar.gz
./
./conffiles
./preinst
./md5sums
./control
./postrm
./prerm
./postinst
$ cat debian-binary
2.0
正如你所看到的,Debian包由3个文件组成:
- debian-binary。这是个文本文件,用来表示.deb所使用的版本。
- control.tar.gz。这个archive中包含了所有的meta信息。比如包的名字和版本。包管理工具能够根据其中一些信息来判断是安装还是卸载,例如系统中已经安装的程序列表。
- data.tar.gz。这个archive中包含了所有的要提取的文件,如二进制文件,文档等。一些包或许会使用其他的压缩格式,这时候该文件的命名将会有所不同(data.tar.bz2 for bzip2, data.tar.xz for XZ, data.tar.lzma for LZMA)。
5.2 .deb的meta信息
.deb中不仅包含了要安装的所有文件,它也描述了同其他包的关系(依赖,冲突,建议等),也提供了在操作包(安装,移除,升级)的脚本。这些包管理工具所需要的信息,不属于被打包的软件,但是存在于包中,我们称之为"meta信息"。
5.2.1 control文件里的描述信息
该文件使用类似于email头的格式(参考RFC 2822)。使用apt工具观察:
Package: apt Version: 0.9.7.9+deb7u2 Installed-Size: 3271 Maintainer: APT Development Team Architecture: amd64 Replaces: manpages-pl (<< 20060617-3~) Depends: libapt-pkg4.12 (>= 0.9.7.9+deb7u2), libc6 (>= 2.4), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.6), debian-archive-keyring, gnupg Suggests: aptitude | synaptic | wajig, dpkg-dev, apt-doc, xz-utils, python-apt Conflicts: python-apt (<< 0.7.93.2~) Description-en: commandline package manager This package provides commandline tools for searching and managing as well as querying information about packages as a low-level access to all features of the libapt-pkg library. . These include: * apt-get for retrieval of packages and information about them from authenticated sources and for installation, upgrade and removal of packages together with their dependencies * apt-cache for querying available information about installed as well as installable packages * apt-cdrom to use removable media as a source for packages * apt-config as an interface to the configuration settings * apt-key as an interface to manage authentication keys Description-md5: 9fb97a88cb7383934ef963352b53b4a7 Tag: admin::package-management, hardware::storage, hardware::storage:cd, implemented-in::c++, interface::commandline, network::client, protocol::ftp, protocol::http, protocol::ipv6, role::program, suite::debian, use::downloading, use::searching, works-with::software:package Section: admin Priority: important Filename: pool/main/a/apt/apt_0.9.7.9+deb7u2_amd64.deb Size: 1261084 MD5sum: 7603385c4f7f8e2bd098bd9a79878403 SHA1: f4129fda11b109122ebe300213d88c92cf2b45a7 SHA256: 36997b52ad31ae481ba9be17d592b6737d29cb11b1357e2061ce5fd57b2635fe
Dependencies:the Depends Field
package header中的Depends Field描述了所有的依赖。Depends Field列出了软件正常运行所需要的所有的条件,利用这些信息,像apt这样的工具就可以安装合适的版本的依赖库。对于每个依赖项,都需要限定它的版本。版本比较操作符如下:
- <<: less than;
- <=: less than or equal to;
- =: equal to (note that “2.6.1” is not equal to “2.6.1-1”);
- >=: greater than or equal to;
- >>: greater than.
Depends Field使用逗号来隔开每个依赖,相当于逻辑与,而'|'用来表示逻辑或(t is an inclusive “or”,not an exclusive “either/or”)。'|'的优先级比','高,因此像“(A or B) and C”这样的依赖关系可以写为:A|B,C。相反,“A or (B and C)” 应该被写为“(A or B) and (A or C)”,因为Depends Field中不接受括号,所以最终被写为“A|B,A|C”。
https://www.debian.org/doc/debian-policy/ch-relationships.html这种机制能够保证软件的正确安装,但是它还有另一个用途:meta-packages,这是一种空的包,包中只含有一些依赖信息。meta-packages能够方便的安装软件所需的依赖库。apt-get install meta-package会自动安装meta-package所描述的所有依赖库。meta-package的使用例子有:gnome,kde-full和linux-image-amd64等。
pre-depends,一种苛刻的依赖描述:
Pre-dependencies依赖信息位于package header的“Pre-Depends” field中,它跟Depends field语法一致。通常的依赖表明依赖库的安装和解包和配置都要在待安装的软件配置之前,而Pre-dependency则要求在待安装软件的安装之前。Pre-dependencies对于apt来说非常苛刻,因为它增加了安装顺序上的约束,因此,如果没有必要就不要使用。甚至,Debian建议在使用Pre-dependencies之前,要咨询debian-devel@lists.debian.org上面的其他开发者。通常都可以找到其他替代解决方案。
Recommends, Suggests, Enhances fields:
Recommends和Suggests描述的依赖都不是强制性的。Recommends中的依赖,用来提高软件的功能,而非必不可少的。Suggests中的依赖,用来对软件提供一些补充。你应该总是安装Recommends中的依赖,除非你明白你为什么不需要它;相反,没有必要安装Suggests中的依赖,除非你知道为什么你需要它。
Enhances中的依赖也属于建议性的,但跟Suggests不同。事实上,Enhances依赖被包含在Suggests依赖中,但不同的是,前者不会对软件做出更改。因此,Enhances经常是指add-on,plug-in之类的扩展。
Conflicts: the Conflicts field
冲突域表明和哪些包不能同时安装。主要原因一般有:包含同样名称的文件,在同一个TCP端口上提供一样的服务,或者会影响彼此的功能。dpkg会拒绝安装有冲突关系的包,除非新的包指明它会替换以存在的包。对于apt-get工具,如果用户选择安装一个包,那么跟它冲突的包就会被卸载掉。
Incompatibilities: the Breaks Field
Breaks域跟Conflicts域差不多,但它还有特别的含义。它意味着软件包的安装可能会“破坏”其他包(或该包的某个版本)。通常这种不兼容的关系不会永久地出现,而且一般具体指的是某些版本不兼容。
如果Breaks域的软件已经安装,那么dpkg就会拒绝安装软件,而apt-get会尝试解决该问题,通过升级不兼容软件的版本。
这种情况一般发生在不再向下兼容的更新上:也就是说新版本不再兼容就版本,如果没有特别说明,则会引起错误。Breaks域的目的就是阻止这种情况的发生。
Provided Items: the Provides Field
Provides域阐述了什么叫“virtual package”。它有两个特性,其中有两个特别重要。其一是通过虚拟的包名关联到具体的包。其二是表明一个包可以完全代替另一个包。因此,利用virtual package可以不用同样的包名来代替。
提供某一个服务。让我们用一个例子讨论第一种情况。所有的邮件服务器,例如postfix或者sendmail都提供 “mail-transport-agent” virtual package。因此,任何需要这种服务的包都可以在域中简单地声明它就可以了。而且,同一台计算机中安装两个邮件服务也没有什么用,所以这些邮件服务的包都会将“mail-transport-agent”放到conflict域中。
virtual packages列表:
为了使virtual package用途更广,每个人都必须遵守相同的名称规定,所以在Debian Policy中将它们标准化了。这个列表包含有:mail-transport-agent表示的邮件服务,c-compiler表示c语言编译器,www-browser表示web浏览器,httpd表示web服务器,ftp-server表示FTP服务器,x-terminal-emulator表示图形界面终端模拟器,x-window-manager表示窗口管理器。完整的列表请查看:
https://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt
能够跟其他包相互替换的能力。当一个包被包含进一个大的包中的时候,Provides域可能会有用。例如,libdigest-md5-perl模块在Perl5.6中可选,但从版本5.8后,该模块就被整合到Perl的包中了。同样,从Perl5.8起,就提供了Provides:libdigest-md5-perl,以便于替换其他版本的Perl。
现有的限制。virtual package有一些限制,最主要的是不能处理virtaul package的版本问题。例如,Depends:libdigest-md5-perl (>=1.6),尽管已经安装了Perl5.10,但打包系统却不认同,尽管事实上满足条件。于是,打包系统会认为版本号不匹配,从而采取了不可预知的冒险的行动。
virtual packages 版本:
尽管现在还不能处理virtual package的版本,但将来会得到支持。事实上,apt已经能够管理virtual package的版本,dpkg将来可能也会支持。届时,我们就能够使用Provides:libstorable-perl (=1.7)来表示某个包提供libstorable-perl 1.7版本同样的功能!
Replacing Files: The Replaces Field
Replaces域是说包中所含的某些文件,也存在于另一个包中,可使用这些文件进行替换。如果没有在Replaces域中声明,则会导致dpkg提示失败(事实上,可以使用--force-overwrite选项强制覆盖)。这能够促使包的维护者认真考虑是否使用Replaces域来防止潜在问题的发生。
当包名称改变或者一个包被包含进另一个包的时候,使用Replaces域是非常正确的。当一个包的维护者决定更新包的文件的时候也是非常有用的,通过Replaces域使得新的文件仅仅在新版本中有效。
当一个包的所有文件都被替换的时候,该包被认为是可移除的。最终会使dpkg移除完全被替换的包。
Tag域:
Tag域不是描述包之间的关系的,而是一种对软件分类的方式。这种依据某些要点(接口的类型,编程语言,程序的使用领域)进行分类的方法已经实施了很长的时间了。尽管如此,很多软件包还没有正确使用它,而且也没有被整合到所有的Debian工具中;aptitude可以显示这些tags,并可以用来作为关键词进行搜索。如果你不喜欢使用aptitude来搜索,可以直接查阅tag数据库:
https://wiki.debian.org/Debtags
5.2.2 配置脚本
另外,control.tar.gz中也可能会包含一些脚本,这些脚本在安装的不同阶段被dpkg调用。在Debian Policy中详细描述了脚本的相关细节。这种处理过程可能会有些复杂,因为一旦一个脚本执行失败,dpkg就会移除软件包或者取消安装。
dpkg数据库:
所有的安装脚本都会放到/var/lib/dpkg/info/目录中,这些脚本文件的名称以包的名字为前缀。同时,该目录中也包含了以.list为后缀的文件,这些文件中保存了对应包的包含的文件列表。
/var/lib/dpkg/status文件中包含了一系列的数据块(前面所提到的mail headers),用来描述每个包。control文件中的信息会被复制到这个文件中。
一般情况下,preinst脚本在包的安装之前调用,prerm脚本在包的移除之前调用,postrm在移除后调用。包的更新相当于移除老版本,并安装新版本。这里我们将讨论包的安装/更新和移除。
约定的脚本名称:
操作序列会调用不同的名称的脚本文件,如old-prerm或new-postinst。对于更新操作来说,prerm脚本包含在老版本软件中,postinst包含在新版本中。
状态图:
Manoj Srivastava制作了一些状态图,用来展示dpkg怎么调用这些配置脚本。在Debian Women项目中也制作了类似的状态图。它们都很容易理解,但是都不全面:
https://people.debian.org/~srivasta/MaintainerScripts.html
https://wiki.debian.org/MaintainerScripts
安装与升级
在安装或升级期间的步骤:
- 对于更新,dpkg会调用old-prerm,upgrade,new-version
- 对于更新,接下来会调用new-preinst,upgrade,old-version;对于首次安装,会调用new-preinst,install。如果包已经安装并移除过,dpkg可能会在最后一个参数中加入老版本。
- 解压,如果一个文件存在,就覆盖它,同时会临时创建一个副本。
- 对于更新,dpkg接下来会调用old-postrm,upgrade,new-version。
- dpkg更新所有的内部文件(包括文件列表,配置脚本等),并删除被替换的文件副本。这个过程不可逆。
- dpkg会更新配置文件(注意不是配置脚本),并询问用户是否能够自动管理安装过程。
- 最后,dpkg会调用new-postinst,configure,last-version-configured。
包的移除
在移除期间的步骤:
- 调用prerm,remove。
- dpkg删除所有文件,除了配置文件和配置脚本。
- 执行postrm,remove。除了postrm,其余脚本都会被删除。如果用户没有选择"purge"选项,那么操作将在这一步骤完成。
- 对于完全移除(dpkg --purge 或 dpkg -p)来说,配置文件也会被删除,连同一些文件副本(*.dpkg-tmp,*.dpkg.old,*.dpkg-new)和一些临时文件;随后,dpkg执行postrm,purge。
purge:
当移除包的时候,配置文件会被保留,以便于再次安装。同样,该程序运行时产生的一些数据通常也会被保留。为了彻底移除,必须使用purge选项,如"dpkg -P","apt-get remove --purge"等。由于使用purge会清楚数据,使用的时候一定要留心。
上面所提到的4个脚本,被一个脚本增强,这个脚本是由使用debconf的包提供的。在安装期间,这个脚本中定义的问题,都会被debconf提问。响应这些问题的答案都会被记录到debconf的数据库中。通常这个脚本被apt调用,先于包的安装。随后pre-和post-脚本会使用这些问题的答案来安装用户的意愿进行操作。
debconf:
debconf的出现是为了解决Debian中的一个反复出现的问题。所有的包在没有postinst执行期间不进行一些交互方式的配置操作的情况下都不能正常工作。但这也会引发一个问题,就是在安装或升级期间,用户必须守护在电脑前来响应各种postinst执行期间提问的问题。由于debconf的出现,这种交互式的方式可以完全丢弃了。
debconf有几个有意思的地方:它要求软件开发人员设置用户交互过程;允许将文本信息以本地语言呈现给用户;有不同的前端显示问题的方式(字符模式,图形模式,非交互模式);允许用户备份这些信息以共享给其他计算机...但是它最重要的功能是,在安装或升级之前呈现这些问题。所以现在用户如果要安装耗时很久的大型软件时,就不必再一直守护在计算机前了。
5.2.3 校验和配置文件
前面已经讲过配置脚本和control文件,但control.tar.gz中可能还有一些有意思的文件。首先,md5sums,包含了所有文件的MD5。它的用途是可以使用debsums来校验安装包是否被修改过。如果这个文件不存在,dpkg会创建一个,并保存起来。
conffiles文件中列出了必须处理的配置文件。管理员可以修改这些配置文件,并且在软件更新时dpkg会尝试保留这些更改。事实上,dpkg处理这种情况的方法很明智:如果两个版本之间的标准配置文件没有被修改,那它什么也不做,反之,dpkg会更新这些修改过得文件。所以分两种情况:第一种是管理员没有修改它们,dpkg会自动安装新版本;第二种情况是,被修改过了,这时候dpkg会询问管理员使用哪个版本的配置文件(老版本的就是修改的配置文件,新版本是使用自己带的)。dpkg还能够显示两者之间的不同地方以帮助用户做出选择。如果用户选择了老版本,新版本的配置文件仍然会被放置在同样的路径中,但文件名以.dpkg-dist为后缀。如果用户选择了新版本,则老版本的文件会加上后缀.dpkg-old。用户也可以在在此期间修改这些文件。
避免交互式选择配置文件:
dpkg处理配置文件更新的时候会以交互式的方式跟用户交互,但一些人不喜欢这种交互式的方式。所以dpkg提供了一些选项:--force-confold,保存老版本配置文件,--force-confnew使用新版本的配置文件,--force-confdef,告诉dpkg让其自主选择操作。这些选项应用在dpkg,但管理员大多时候使用的是apt-get或aptitude。所以有必要了解下它们的对应的命令。
apt-get -o DPkg::options::="--force-confdef" -o DPkg::options::="--force-confold" dist-upgrade
这些选项可以直接存储在apt的配置中。做法是将下面的这行添加到/etc/apt/apt.conf.d/local文件中:
DPkg::options { "--force-confdef"; "--force-confold";}
这样一来,图形界面的程序也能这样使用了,例如aptitude。
强制dpkg使用交互式选择配置文件:
--force-confask选项要求dpkg显示选择配置文件的问题。因此,当重新安装包时,dpkg会针对所有的已修改的配置文件向用户进行提问。有时候这种用法会很方便,例如配置文件被删除,要重新安装这些原始的配置文件,这时候就可以使用--force-confask选项了。因为如果dpkg用的是普通模式的话,它会认为配置文件的移除是一种正确的修改操作,所以不会重新安装用户需要的配置文件。
5.3 源码包
5.3.1 源码包的格式
源码包通常由3个文件构成,.dsc,.orig.tar.gz和.debian.tar.gz(或.diff.gz)。用户可以从源码包中构建程序。.dsc(Debian Source Control)文件的内容包含了RFC 2822头,它描述了源码包和指定了其他哪些文件是其中的一部分。这是由源码包的维护者提供的,以确保其正确。其中也包含了源码包的所有依赖的软件(Build-Depends),利用这些软件来编译构建程序。
Hash: SHA256
Format: 3.0 (quilt)
Source: zim
Binary: zim
Architecture: all
Version: 0.48-1
Maintainer: Emfox Zhou
Uploaders: Raphaël Hertzog
Homepage: http://zim-wiki.org
Standards-Version: 3.9.0
Vcs-Browser: http://svn.debian.org/wsvn/collab-maint/deb-maint/zim/trunk?op=log
Vcs-Svn: svn://svn.debian.org/collab-maint/deb-maint/zim/trunk
Build-Depends: debhelper (>= 7.4.12), python-support (>= 0.8), xdg-utils, python (>=2.5), libgtk2.0-0 (>= 2.6), python-gtk2, python-xdg, python-simplejson | python (>= 2.6)
.....略
名称的区分:
需要注意的是,源码包的名称跟生成的二进制包的名称没有对应关系。一个源码包可能会生成几个二进制包。因此,.dsc文件中使用Source和Binary两个域来显式指定它们的名称。
一个源码包为什么要生成几个二进制包?
一个程序的源码包通常会产生几个二进制包。这样做可以满足不同使用环境。例如,一个共享库,它可以用在发布程序中(libc6),也可以用来开发程序(libc6-dev);对于某种服务,我们可能在一台计算机中安装它的服务端,在另一台计算机中安装它的客户端,如openssh。
不同的源码包格式:
起初只有一种源码包格式,也就是1.0版本,它将.org.tar.gz与.diff.gz联系到一起(也存在一种变体,它只包含一个单独的.tar.gz文件,如果.org.tar.gz不可用的时候就会使用这个文件)。自从Debian Squeeze版本后,Debian开发人员可以选择使用新的格式了。3.0版本可以将多个存档文件放到同一个源码包中:除了.orig.tar.gz之外,还有附加的.orig-COMPONENT-tar.gz。这对于想发布不同组件的软件来说就很有用了。
.orig.tar.gz文件中的源码是原始作者提供的。它告诉包的维护人员,不要试图修改这个文件,因为这样的话可以保持原始版本的完整性,方便校验,也是对这些作者的尊重。
.debian.tar.gz(或.diff.gz)文件包含了对原始版本的修改,很多包维护人员会添加一个目录,目录里包含了构建包的指令。
源码包的解压缩:
你可以这样解压缩:
$ dpkg-source -x package_0.7-1.dsc
你也可以使用apt-get下载源码包并解包,但是这要求在/etc/apt/sources.lists文件中添加deb-src信息。添加后,你就可以这样使用了:
$ apt-get source package
5.3.2 源码包的使用
源码包是Debian系统中软件的基础,所有软件包都来自于对应的源码包,任何软件包的更改都来自于源码包的更改。当一个新版本发布到Debian服务器时,源码包是最重要的。不同架构的计算机用户下载源码包,并编译成各种架构的软件。包的开发者可能也会同时发布几种已经编译好的二进制包,通常是i386和amd64,但这相对来说不是必要的,毕竟用户可以使用源码包自动生成程序。
5.4 使用dpkg
dpkg是一条很基础的命令。如果你有一个.deb,你可以使用dpkg来安装或分析它。但dpkg能够做的仅仅是一部分:它知道系统中已安装的包,虽然在命令行中指定了包,但它不能处理其他的可用的包。例如,它不能够处理依赖包。相反地,apt-get可以创建一个依赖包的列表,并自动安装它们。
dpkg还是apt-get?
我们应当把dpkg当作一个系统工具(后端的),把apt-get当作与用户更亲近的工具。这些工具协同工作,每个都有不同的使用场景。
5.4.1 包的安装
注意,dpkg这个工具,只能安装已经下载的包,因为它不会自动下载/安装任何其他包。使用-i或-install选项来进行安装:
(Reading database ... 96357 files and directories currently installed.)
Preparing to replace man-db 2.6.1-3 (using man-db_2.6.2-1_amd64.deb) ...
Unpacking replacement man-db ...
Setting up man-db (2.6.2-1) ...
Building database of manual pages ...
可以看到dpkg处理的几个步骤,因此如果安装过程发生错误,我们就能够定位在哪一步中出错。安装过程的核心的两个步骤:解包和配置。apt-get可以高效地使用dpkg,可以减少调用dpkg的次数(每次调用都是有代价的,因为需要加载数据库数据到内存中,尤其是已经安装的文件列表)。
(Reading database ... 96357 files and directories currently installed.)
Preparing to replace man-db 2.6.2-1 (using man-db_2.6.2-1_amd64.deb) ...
Unpacking replacement man-db ...
# dpkg --configure man-db
Setting up man-db (2.6.2-1) ...
Building database of manual pages ...
有时dpkg在安装过程中会产生错误,如果用户选择忽略,dpkg将会产生一个警告;所以,针对这种情况,dpkg有不同的--force-*选项。使用dpkg --force-help命令,或者dpkg的手册中可以看到这些选项的全部描述。最常见的错误是文件冲突。当一个包包含一个已经存在的文件的时候,dpkg就会报错。请看下面的例子:
dpkg: error processing /var/cache/apt/archives/libgdm_3.8.3-2_amd64.deb (--unpack):
trying to overwrite '/usr/bin/gdmflexiserver', which is also in package gdm3 3.4.1-9
这种情况下,如果你觉得覆盖文件没有影响,那么你可以使用--force-overwrite选项,它告诉dpkg忽略这个错误并覆盖该文件。
--force-*选项有很多种,但只有--force-overwrite比较常用。其他的这些选项,用在非常不常见的情况下,遇到这些情况的时候,最好是不要强制干涉这些问题,不要破坏包处理的常规机制,以确保系统的一致性和稳定性。
正确使用--force-*
如果你不够小心,不当地使用--force-*可能会导致APT工具拒绝工作!事实上,一些选项能够允许在包的依赖不存在或是有冲突的时候继续安装。但这样做会导致系统处于inconsistent状态,APT工具集会拒绝任何操作,直到系统恢复到consistent状态(通常是安装缺少的依赖或者移除这个有问题的包)。例如,安装rdisktop的时候忽略缺少libc6库的问题,会有如下的结果:
# apt-get dist-upgrade
[...]
You can run "apt-get -f install" to correct these problems.
The following packages contain unmet dependencies:
rdesktop: Depends on: libc6 (>= 2.5) but 2.3.6.ds1-13 etch7 is installed
E: missing dependencies. Try to use the option -f.
一个自信的管理员遇到缺少依赖库或冲突的时候,可能会使用--force-*选项来忽略这个错误。这时候,如果还想继续使用apt-get或aptitude,他们必须编辑/var/lib/dpkg/status,删除或修改缺少的依赖或冲突。
这种处理方法是非常不好的,应当杜绝,除非到了迫不得已的时候。通常,好的解决办法是重新编译出现问题的包或使用新的版本。
5.4.2 包的移除
dpkg使用-r或--remove选项来移除包。然而这种移除是不彻底的:所有的配置文件,维护脚本,日志和其他的用户数据不会被移除。如果要完全移除,则使用-P或--purge选项。
5.4.3 查看dpkg数据库和.deb文件
- --listfiles package(或-L):列出一个包所安装的所有文件
- --search file(或-S):找出包含该文件的所有的包
- --status package(或-s):显示已安装的包的头信息
- --list file(或-l):列出系统所知道的所有的包,及其安装状态
- --contents file.deb(或-c):列出file.deb中的文件
- --info file.deb(或-I):列出file.deb中的头信息
版本比较
自从dpkg用作处理deb包后,dpkg就提供了版本比较的功能。这就是为什么dpkg提供了一个--compare-versions的选项,通常在配置脚本中这么使用。该选项要求三个参数:第一个版本号,操作符,第二个版本号。这些操作符有:lt(strictly less than),le(less than or equal to), eq(equal), ne(not equal), ge(greater than or equal to),gt(strictly greater than)。如果比较正确,返回0,否则返回非0.
5.4.4 dpkg的日志文件
dpkg的所有操作日志都保存在/var/log/dpkg.log中。这个日志文件中记录的信息非常详细。通过追踪dpkg日志,首先,能够帮助开发人员跟踪任何时候包的操作对系统的改变。另外,所有的版本都被记录下来,所以很容易核查changelog.Debian.gz或已修复的bug。
5.4.5 支持Multi-Arch
所有Debian包的control中都有一个Architecture域,它要么是"all",要么是特定的架构名。前一种情况下用“all”表示适合所有的架构。后一种情况,默认情况下,dpkg只允许安装跟主机相同的架构的包,使用"dpkg --print-architecture"可查看主机架构。这种限制能够防止用户安装错误架构的软件。
启用Multi-Arch
启用Multi-Arch,可以使用户安装其他架构的包。通过“dpkg --add-architecture”实现,也有一个对应的选项:--remove-architecture,用来删除一个其他架构,但仅仅在没有该架构的软件存在的时候才可以使用。
在amd64上运行i386程序
使用Multi-Arch最常见的情况是在amd64系统中运行i386程序。特别是很多软件(skype)仅仅提供了32位版本。在Multi-Arch以前,要这样做必须事先安装ia32-libs,之后系统中就有了32位的库。
Multi-Arch带来的变化
为了使Multi-Arch有用和易用,所有的库必须重新打包,并将它们拷贝到特定架构的目录下。因此,更新的包中如果包含 Multi-Arch:same 头,则表示该包的各种架构版本都可以一起安装。Multi-Arch从Debian Wheezy版本才开始首秀,所以不是所有的库都能够如此处理。
dpkg-query: error: --status needs a valid package name but 'gcc-4.7-base' is not:ambiguous package name 'gcc-4.7-base' with more than one installed instance
Use --help for help about querying packages.
# dpkg -s gcc-4.7-base:amd64 gcc-4.7-base:armhf | grep ^Multi
Multi-Arch: same
Multi-Arch: same
# dpkg -L libgcc1:amd64 |grep .so
/lib/x86_64-linux-gnu/libgcc_s.so.1
# dpkg -S /usr/share/doc/gcc-4.7-base/copyright
gcc-4.7-base:armhf, gcc-4.7-base:amd64: /usr/share/doc/gcc-4.7-base/copyright
值得注意的是,Multi-Arch:same包必须使用包名和架构组成的名称。同一个包的不同架构之间可以共享文件;当文件被共享的时候,dpkg能够确保所有的包的文件的正常。包的所有架构版本,都要统一为一个版本,它们必须作为一个整体进行升级。
Multi-Arch的支持,在处理依赖方面带来了一些有意思的挑战。要想满足依赖,包必须使用"Multi-Arch:foreign",或该包的架构匹配依赖中的一个。使用package:any语法,可以允许任何架构的包来满足该依赖,但是如果其他架构的包使用了Multi-Arch:allowed,它们才能满足依赖关系。
5.5 与其他包管理系统的共存
Debian包管理不是Linux世界中唯一的包管理方式,还有另一种:RPM,它存在于Red Hat系统及其派生系统。Red Hat是一个非常受欢迎的商业发行版。因此,第三方提供的软件,更多地会采用RPM方式。这时候,你应当了解Debian中的rpm软件包,它能够在Debian系统中处理RPM包。但使用它的时候有一些限制。事实上,使用rpm安装RPM包是不合理的;RPM使用自己特有的数据库,不同于Debian。这就是不能确保两种包管理系统稳定共存的原因。另外,通过alien可以将RPM转换为.deb包。
鼓励使用.deb
如果你经常使用alien来安装RPM,那么你不要犹豫地给软件提供商提出建议,表明你更希望.deb格式的安装包。要注意的是不是转换成.deb包格式就可以,因为.deb包还有很多细节:要注意alien转换的.deb或专门构建的的.deb版本跟你所使用的Debian版本是否相同,还有如果是Debian的派生发行版如Ubuntu,它们处理.deb的能力跟Debian有可能不尽相同,尤其是Wheezy。
phpmyadmin_2.0.5-2_all.deb generated
# ls -s phpmyadmin_2.0.5-2_all.deb
64 phpmyadmin_2.0.5-2_all.deb
正如你所看到的,使用非常简单。然而,转换生成的.deb包中是没有依赖信息的,因为RPM和.deb这两种格式中的依赖信息不能够完全正确对应起来。管理员必须亲自确保转换后的包能够正确工作,这就是为什么在Debian系统中尽量避免使用这种方法。幸运的是,Debian本身就包含了大量的软件,以满足你的需要。
通过查看alien的man手册,你会看到alien也能够处理其他格式的包,尤其是Slackware发行版所使用的包。
使用dpkg能够提高系统的稳定性。APT工具集不仅集成了这种好处,它还能够减轻管理员的包管理工作。