deb包解析与打包

[TOC]

一、deb包结构

deb包中有两部分信息:

  1. 数据:在安装过程中直接拷贝到系统中的文件
  2. 控制:在安装和卸载过程中执行的脚本,为dpkg提供的包信息

以本次打包的openssh为例:

1
2
3
4
5
6
7
8
9
10
11
.
├── DEBIAN
│   ├── control
│   ├── postinst
│   └── prerm
├── etc
│   └── ssh
├── usr
│   └── local
└── var
└── empty

包目录中的DEBIAN目录中包含的就是控制信息,其它目录是数据信息,其它目录会被直接拷贝到系统根目录。

1) control文件

DEBIAN中的控制信息最重要的是control文件,以下是本次打包的openssh的control文件

1
2
3
4
5
6
7
8
Package: ebaina-openssh
Version: 9.3p1
Architecture: arm64
Maintainer: Ebaina Developers
Installed-Size: 6247
Depends: ebaina-zlib,ebaina-openssl,ebaina-haveged
Priority: optional
Description: build by Ebaina

其中:

  1. Package: 包名,使用dpkg安装后可通过dpkg -l查看安装的包
  2. Version: 软件版本
  3. Architecture:软件运行架构
  4. Maintainer:维护者
  5. Installed-Size:安装大小
  6. Depends: 软件的依赖项(包名),多个依赖项使用逗号隔开。可以指定依赖的版本
  7. Description:对软件包的描述,若描述打包时会报警告

2) 脚本

有四个脚本可以执行:preinst postinst prerm psotrm。分别在安装之前,安装之后,删除之前与删除之后执行。通过这些脚本可以在软件安装和卸载时自动执行一些其它操作,比如配置开机启动等。这些脚本只需添加可执行权限放在DEBIAN目录下即可。

二、deb打包与解包

如果对deb包还不够了解,可以下载deb包并解包,有利于进一步分析。

1
2
# apt 下载软件包但不安装(不需要管理员权限)
apt -d download ssh

可以在当前目录看到软件包ssh_1%3a7.6p1-4ubuntu0.7_all.deb(可能版本不同)

1
2
3
4
5
6
7
# 创建存储解包文件的目录
mkdir ssh

# deb解包数据文件,解包到ssh目录下
dpkg -x ssh_1%3a7.6p1-4ubuntu0.7_all.deb ssh/
# deb解包控制文件
dpkg -e ssh_1%3a7.6p1-4ubuntu0.7_all.deb ssh/DEBIAN

为了详细了解DEBIAN的结构,可以下载不同的包分析共性。

打deb包

1
2
3
4
# pack dir:指定打包的目录
# pack file name:指定包的文件名(与包名无关),若省略则在目录名后加.deb后缀作为文件名
# dpkg -b <pack dir> [pack file name]
dpkg -b openssh

三、deb包的安装与包状态

安装与卸载软件包

1
2
3
4
5
6
7
8
9
# 安装软件包
# dpkg -i <pack file name>
dpkg -i openssh.deb

# 卸载软件包
# dpkg -r <pack name>
dpkg -r ebaina-openssh

# 【注】:安装时指定的是包的文件名,卸载时指定包名
1
2
# dpkg 允许同时安装多个软件包,dpkg会自行分析依赖,而不必按依赖顺序逐个安装
dpkg -i *.deb

查看包状态

1
dpkg -l
1
2
3
4
5
6
    Name           Version
+++-==============-==============
ii ebaina-openssh 9.3p1
ii ebaina-zlib 1.2.13
ii ebaina-openssl 1.1.1l
ii ebaina-haveged 1.9.2

第一列表示软件包的状态,格式如下期望状态|当前状态|错误状态

  1. 期望状态

    • u:即 unknown,软件包未安装且用户未请求安装

    • i:即 install,用户请求安装该软件包

    • r:即 remove,用户请求卸载该软件包

    • p:即 purge,用户请求卸载该软件包并清理配置文件

    • h:即 hold,用户请求保持续当前软件包版本

  2. 当前状态

    • n:即 not-installed,软件包未安装
    • i:即 installed,软件包已安装并完成配置
    • c:即 config-files,软件包已经被卸载,但是其配置文件未清理
    • u:即 unpacked,软件包已经被解压缩,但还未配置
    • f:即 half-configured,配置软件包时出现错误
    • w:即 triggers-awaited,触发器等待
    • t:即 triggers-pending,触发器未决
  3. 错误状态

    • h:软件包被强制保持
    • r:即 reinstall-required,需要卸载并重新安装
    • x:软件包被破坏

dpkg的工作目录

这里说的工作目录是dpkg在运行时存储各种包信息的目录:/var/lib/dpkg。其中包含status文件以及info目录。

在info目录中包含软件包的文件列表<pack name>.list,在卸载软件包时会根据文件列表将文件删除。

除此之外还有各个软件包的脚本<pack name>.<script name>,例如:ebaina-openssh.postinst

dpkg目录中的status则存储了每个软件包信息及其状态。

四、其它问题

  1. 无法卸载,提示Terminated

    问题现象:

    1
    2
    3
    Removing ebaina-haveged (1.9.2)...
    Terminated
    haveged: haveged: Stopping due to signal 15

    问题分析:在卸载时需要关闭对应的进程,所以在prerm脚本中通过ps加grep的方式查找进程PID,由于dpkg在卸载时的进程名也会包含包名。所以搜索出多个PID一起被杀死。其中包含dpkg卸载软件包的进程:

    1
    2
    1750 root      0:00 dpkg -r ebaina-haveged
    1751 root 0:00 {ebaina-haveged.} /bin/sh /var/lib/dpkg/info/ebaina-haveged.prerm

    因此只需要在使用grep时避免将dpkg的进程包含在内即可

    问题解决:

    1
    2
    3
    HAVEGED_PID=`ps -e | grep -v grep | grep "haveged" | awk '{print $1}'`
    # 改为
    HAVEGED_PID=`ps -e | grep -v grep | grep "/haveged" | awk '{print $1}'`

五、参考文章

  1. Ubuntu 系统 dpkg 命令使用详解
0%