我们在安装一个Debian包的时候,在安装或者卸载的过程中可能需要处理一些额外的安装操作,比如:创建一个新的目录,停止一个正在运行的服务等等。这是使用称为“维护者脚本”的特殊脚本的地方。顾名思义,这是我们开发人员经常使用的脚本。常见的维护者脚本错误●“dpkg(subprocess):unabletoexecuteinstalledpost-installationscript(/var/lib/dpkg/info/xxx.postinst)”●上面的错误应该是很常见的,就是在安装时进行维护或脚本错误。这些脚本如下所述。一、四种maintainer脚本文件“preinst,postinst,prermandpostrm”1.基本描述binarypackage.preinst,binarypackage.postinst,binarypackage.prerm,binarypackage.postrm这四类文件称为maintainer脚本,这些脚本都放在Debian目录的一个受控区域,由“dpkg”用来控制安装、升级和删除。2.特定功能这些文件是可执行脚本,在安装或删除软件包之前或之后自动运行。所有这些文件都是Debian档案库“control”部分的一部分,还有一个名为control的文件。下面的foo指的是二进制安装包的名称。01foo.preinst:安装前脚本这个脚本在它所属的包从deb文件中解压出来之前执行。许多preinst脚本停止为正在升级的包提供服务,直到它们的安装或升级完成。02foo.postinst:软件安装后执行的脚本一旦foo从其deb文件中解压缩,此脚本通常会在安装包foo后执行必要的配置工作。通常,postinst脚本会要求用户输入,或者警告用户如果他们接受默认值,他们应该记得返回并根据需要重新配置包。许多postinst脚本在脚本中执行命令,以便在安装或升级新包后启动或重新启动服务。03foo.prerm:卸载软件前执行的脚本此脚本通常会停止与包关联的任何守护进程,它在卸载包的关联文件之前执行。04foo.postrm:卸载软件后执行的脚本这个脚本通常修改链接或其他与foo相关的文件,或者删除软件包创建的文件。所有当前的控制文件都可以在/var/lib/dpkg/info目录中找到。foo包关联的文件以名称“foo”开头,并具有相应的文件扩展名“preinst”、“postinst”等。3.maintainer脚本的执行过程当您执行安装或卸载命令时,执行顺序maintainer脚本如下:●第一次安装deb包时,执行“dpkg-itest_v1.deb”安装,Debian下控制脚本按如下顺序执行:preinst-->postinst如果卸载deb但保留配置文件,执行“dpkg-rtest”,Debian下面的控制脚本按如下顺序执行:prerm-->postrm如果卸载不保留配置文件,执行“dpkg-Ptest”,如下Debian中控制脚本的执行顺序是:prerm-->postrm-->postrm,你觉得错了吗?其实并没有,它只是执行了两次postrm。但是第一次执行postrm传入的$1是remove,第二次执行postrm传入的$1是purge。有关更详细的说明,请参阅dpkg命令的手册页。●如果升级安装,例如执行dpkg-itest_v2.deb,Debian下控制脚本的执行顺序为:prerm-->preinst-->postrm-->postinst4。注意事项作为维护人员,您应该避免手动编辑维护者脚本,因为它们经常会出现各种问题。如果您违背建议并自己为软件包创建和自定义维护程序脚本,则必须确保不仅测试安装和升级,还测试删除和清除。如果一个包使用这些需要严格测试的维护者脚本,请确保不仅要测试安装,还要测试删除、清除和升级。当卸载或完全删除包时,许多维护者脚本错误会自行显现。整个测试过程应按照以下操作顺序完成:●如果可能,请安装上一版本的软件包。●升级之前版本的软件包;●将软件包降级到以前的版本(可选);●彻底删除包;●全新安装包;●卸载软件包;●重新安装软件包;●完全取出包装。二、配置文件列表Conffiles1.基本描述这部分是对Debian软件包的一些扩展知识。那么什么是配置文件?Conffiles是一个配置文件列表(通常放在“/etc”中),当包升级时不会被包管理系统覆盖。这确保了这些文件内容的本地值将被保留,这是一个关键功能,可以在运行的系统上对包进行就地升级。要确定在升级过程中保存了哪些文件,请运行“dpkg--statuspackage”并查看配置文件。conffiles的作用是在软件包升级时,不同于其他文件只需要简单的暴力覆盖即可。放在“/etc”下的(配置)文件需要特别考虑,是保留旧配置还是使用新配置,所以有了这个特殊的行为。我经常遇到修改配置文件。软件包升级时,出现如下查询窗口:配置文件'/etc/default/nginx'==>自安装以来修改(由您或脚本)。==>软件包分发者已发布更新版本。你想怎么办?您的选择是:Y或I:安装软件包维护者的版本N或O:保留您当前安装的版本D:显示版本之间的差异Z:启动shell来检查情况默认操作是保留当前版本。*nginx(Y/I/N/O/D/Z)[默认=N]?解压nginx-common的deb包,可以看到里面有Conffiles文件,里面存放的所有文件都要放在“/etc”下。2.原理分析首先,Conffile是指Conffiles文件中维护的/etc下的任意文件。使用“dpkg”安装Deb包时(apt/aptitute同理),文件中涉及三个hash值(这里加缩写):01hash_real:一个conffile的实际hash02hash_old:thehashmaintainedbyaconffilewhenaoldversioninstalled(维护在/var/lib/dpkg/status文件中,可以通过命令dpkg--statusConffiles查看指定包)03hash_new:一个hash的一般逻辑待安装的新版本中的conffile如下:先比较hash_old和hash_new,如果相同则保持原样(这是我一开始遇到的问题,误删了某一个Conffile,在新旧版本中没有改变,所以保持不变,即继续不存在);如果Conffile不存在,配置了--force-confmiss,则重新安装该文件(这是解决上面遇到的问题);判断hash_real和hash_old是否一致,如果不一致,则标记为"useredited”,即用户修改了Conffile;hash_real和hash_new一致,不一致则标记为disedited,即软件包升级会修改Conffile;然后进入提示链接,即根据这些状态和dpkg的选项判断是交互询问是否覆盖还是直接改;如果用户没有修改过Conffile,软件包升级会改变这个文件,任何--force-选项都没有用,Conffile会自动更新;如果用户修改了Conffile,包升级不会改变这个文件,可以输入--force-confask提示是使用旧配置还是新配置;如果用户修改了Conffile,包升级会改变这个文件,那么默认是Confask的行为。这时候也可以通过“confold/confnew/confdef”取消查询步骤。3、总结对于Deb包升级时文件的更新机制,dpkg有一套默认的方案:所有放在“/etc”目录下的文件都归类为Conffile,此类文件的升级方式大致如下:用户不修改Conffile,软件包升级会改变这个文件,Conffile会自动更新;如果用户修改了Conffile,软件包升级不会改变这个文件,deb包升级时deb包不会更新这个文件,并保存用户修改后的状态;如果用户修改了Conffile,软件包升级会改变这个文件,那么confask的行为是默认的,安装时会询问用户是使用最新的文件还是用户修改的文件;所以Deb包的开发者要注意这个规范,将需要保存用户配置的文件放在“/etc”目录下。以上是《Debian包的潜规则(脚本篇)》的全部内容。如果您有任何问题或建议,欢迎留言告诉我们~本文投稿人:庞毅,麒麟团队
