Starting from dpkg deb package, this paper analyzes the content of deb package and the process of dpkg installation package

Posted by chuddyuk on Fri, 24 Dec 2021 02:46:52 +0100

Download dpkg deb package

Execute apt get download dpkg to download the deb package of dpkg program:

longyu@virt-debian10:/tmp$ sudo apt-get download dpkg
longyu@virt-debian10:/tmp$ ls -lh ./dpkg_1.19.7_amd64.deb 
-rw-r--r-- 1 root root 2.2M 6 April 2019 ./dpkg_1.19.7_amd64.deb

1.19. 7 is the version of dpkg package, and amd64 represents the applicable architecture of the package.

deb content

file deb package example:

longyu@virt-debian10:/tmp$ file ./dpkg_1.19.7_amd64.deb 
./dpkg_1.19.7_amd64.deb: Debian binary package (format 2.0)

You can see that the deb package in the example is a Debian binary package in 2.0 format.

Important information obtained by man deb:

FORMAT
       The file is an ar archive with a magic value of !<arch>.  Only the common ar archive format is supported, with no long file name extensions, but with file  names
       containing  an  optional  trailing  slash,  which limits their length to 15 characters (from the 16 allowed).  File sizes are limited to 10 ASCII decimal digits,
       allowing for up to approximately 9536.74 MiB member files.

       The tar archives currently allowed are, the old-style (v7) format, the pre-POSIX ustar format, a subset of the GNU format (new  style  long  pathnames  and  long
       linknames,  supported  since  dpkg  1.4.1.17;  large  file  metadata  since  dpkg  1.18.24), and the POSIX ustar format (long names supported since dpkg 1.15.0).
       Unrecognized tar typeflags are considered an error.  Each tar entry size inside a tar archive is limited to 11 ASCII octal digits, allowing for up to 8  GiB  tar
       entries.  The GNU large file metadata support permits 95-bit tar entry sizes and negative timestamps, and 63-bit UID, GID and device numbers.

       The first member is named debian-binary and contains a series of lines, separated by newlines. Currently only one line is present, the format version number, 2.0
       at the time this manual page was written.  Programs which read new-format archives should be prepared for the minor number to be increased and new  lines  to  be
       present, and should ignore these if this is the case.

       If  the  major  number  has  changed,  an incompatible change has been made and the program should stop. If it has not, then the program should be able to safely
       continue, unless it encounters an unexpected member in the archive (except at the end), as described below.

       The second required member is named control.tar.  It is a tar archive containing the package control information, either not  compressed  (supported  since  dpkg
       1.17.6),  or  compressed with gzip (with .gz extension) or xz (with .xz extension, supported since 1.17.6), as a series of plain files, of which the file control
       is mandatory and contains the core control information, the conffiles, triggers, shlibs and symbols files contain optional control information, and the  preinst,
       postinst, prerm and postrm files are optional maintainer scripts.  The control tarball may optionally contain an entry for '.', the current directory.

       The  third,  last  required  member  is  named  data.tar.   It contains the filesystem as a tar archive, either not compressed (supported since dpkg 1.10.24), or
       compressed with gzip (with .gz extension), xz (with .xz extension, supported since dpkg 1.15.6), bzip2 (with .bz2 extension, supported  since  dpkg  1.10.24)  or
       lzma (with .lzma extension, supported since dpkg 1.13.25).

       These members must occur in this exact order. Current implementations should ignore any additional members after data.tar.  Further members may be defined in the
       future, and (if possible) will be placed after these three. Any additional members that may need to be inserted after debian-binary  and  before  control.tar  or
       data.tar and which should be safely ignored by older programs, will have names starting with an underscore, '_'.

       Those  new  members  which won't be able to be safely ignored will be inserted before data.tar with names starting with something other than underscores, or will
       (more likely) cause the major version number to be increased.

The above description shows that the deb package is a package with magic values! ar package. It consists of three parts:

  1. debian-binary
  2. control.tar
  3. data.tar

Debian binary stores the deb format version number, which is currently version 2.0.

control.tar stores the control information of the package. It packages coffiles, triggers, shlibs, symbols and other files, which contain optional control information, as well as optional deployment scripts such as preinst, postinst, prerm and postrm.

data.tar is the tar package that installs files in the file system.

The order of these three items is fixed and cannot be reversed. The current implementation ignores data After tar.

Dpkg DEB command

The dpdk deb command is used to process deb packages. The functions described in manual are as follows:

       dpkg-deb actions
              See dpkg-deb(1) for more information about the following actions.

              -b, --build directory [archive|directory]
                  Build a deb package.
              -c, --contents archive
                  List contents of a deb package.
              -e, --control archive [directory]
                  Extract control-information from a package.
              -x, --extract archive directory
                  Extract the files contained by package.
              -X, --vextract archive directory
                  Extract and display the filenames contained by a
                  package.
              -f, --field  archive [control-field...]
                  Display control field(s) of a package.
              --ctrl-tarfile archive
                  Output the control tar-file contained in a Debian package.
              --fsys-tarfile archive
                  Output the filesystem tar-file contained by a Debian package.
              -I, --info archive [control-file...]
                  Show information about a package.

Dpkg DEB - C execution example

root@virt-debian10:/tmp# dpkg-deb  -c ./dpkg_1.19.7_amd64.deb 
drwxr-xr-x root/root         0 2019-06-04 05:22 ./
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/alternatives/
-rw-r--r-- root/root       100 2019-06-04 05:22 ./etc/alternatives/README
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/cron.daily/
-rwxr-xr-x root/root      1187 2019-04-19 10:14 ./etc/cron.daily/dpkg
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/dpkg/
-rw-r--r-- root/root       446 2014-11-28 09:08 ./etc/dpkg/dpkg.cfg
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/dpkg/dpkg.cfg.d/
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/logrotate.d/
-rw-r--r-- root/root       120 2019-04-19 10:14 ./etc/logrotate.d/alternatives
-rw-r--r-- root/root       112 2019-04-19 10:14 ./etc/logrotate.d/dpkg

Dpkg DEB - e execution example

root@virt-debian10:/tmp/test# dpkg-deb  -e ./dpkg_1.19.7_amd64.deb 
root@virt-debian10:/tmp/test# ls
DEBIAN	dpkg_1.19.7_amd64.deb
root@virt-debian10:/tmp/test# cat DEBIAN/
conffiles  control    md5sums    postinst   postrm  

Dpkg DEB - x execution example

root@virt-debian10:/tmp/test# dpkg-deb  -x ./dpkg_1.19.7_amd64.deb  ./package
root@virt-debian10:/tmp/test# ls ./package/
etc  sbin  usr	var

Dpkg DEB - x execution example

root@virt-debian10:/tmp/test# dpkg-deb -X ./dpkg_1.19.7_amd64.deb  package
./
./etc/
./etc/alternatives/
./etc/alternatives/README
./etc/cron.daily/
./etc/cron.daily/dpkg
./etc/dpkg/
./etc/dpkg/dpkg.cfg
./etc/dpkg/dpkg.cfg.d/
./etc/logrotate.d/
./etc/logrotate.d/alternatives
./etc/logrotate.d/dpkg
.........

Dpkg DEB - f execution example

root@virt-debian10:/tmp/test# dpkg-deb -f ./dpkg_1.19.7_amd64.deb 
Package: dpkg
Version: 1.19.7
Architecture: amd64
Essential: yes
Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
Installed-Size: 6693
Pre-Depends: libbz2-1.0, libc6 (>= 2.15), liblzma5 (>= 5.2.2), libselinux1 (>= 2.3), zlib1g (>= 1:1.1.4)
Depends: tar (>= 1.28-1)
Suggests: apt, debsig-verify
Breaks: acidbase (<= 1.4.5-4), amule (<< 2.3.1+git1a369e47-3), beep (<< 1.3-4), im (<< 1:151-4), libapt-pkg5.0 (<< 1.7~b), libdpkg-perl (<< 1.18.11), lsb-base (<< 10.2019031300), netselect (<< 0.3.ds1-27), pconsole (<< 1.0-12), phpgacl (<< 3.3.7-7.3), pure-ftpd (<< 1.0.43-1), systemtap (<< 2.8-1), terminatorx (<< 4.0.1-1), xvt (<= 2.1-20.1)
Section: admin
Priority: required
Multi-Arch: foreign
Homepage: https://wiki.debian.org/Teams/Dpkg
Description: Debian package management system
 This package provides the low-level infrastructure for handling the
 installation and removal of Debian software packages.
 .
 For Debian package development tools, install dpkg-dev.

Dpkg DEB -- Ctrl tarfile execution example

root@virt-debian10:/tmp/test# dpkg-deb --ctrl-tarfile ./dpkg_1.19.7_amd64.deb > control.tar
root@virt-debian10:/tmp/test# tar -tvf ./control.tar 
drwxr-xr-x root/root         0 2019-06-04 05:22 ./
-rw-r--r-- root/root       117 2019-06-04 05:22 ./conffiles
-rw-r--r-- root/root       976 2019-06-04 05:22 ./control
-rw-r--r-- root/root      8877 2019-06-04 05:22 ./md5sums
-rwxr-xr-x root/root       789 2019-06-04 05:22 ./postinst
-rwxr-xr-x root/root       498 2019-06-04 05:22 ./postrm

Dpkg DEB -- Fsys tarfile execution example

root@virt-debian10:/tmp/test# dpkg-deb --fsys-tarfile ./dpkg_1.19.7_amd64.deb > data.tar
root@virt-debian10:/tmp/test# tar -tvf ./data.tar
drwxr-xr-x root/root         0 2019-06-04 05:22 ./
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/alternatives/
-rw-r--r-- root/root       100 2019-06-04 05:22 ./etc/alternatives/README
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/cron.daily/
-rwxr-xr-x root/root      1187 2019-04-19 10:14 ./etc/cron.daily/dpkg
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/dpkg/
.........

Dpkg DEB - I execution example

root@virt-debian10:/tmp/test# dpkg-deb -I ./dpkg_1.19.7_amd64.deb 
 New format Debian Package, format version 2.0. 
 Size 2208136 bytes: master control package=4424 Bytes.
     117 Bytes,    5 lines      conffiles            
     976 Bytes, 19 lines      control              
    8877 Bytes, 123 lines      md5sums              
     789 Bytes, 46 lines   *  postinst             #!/bin/sh
     498 Bytes, 36 lines   *  postrm               #!/bin/sh
 Package: dpkg
 Version: 1.19.7
 Architecture: amd64
 Essential: yes
 Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
 Installed-Size: 6693
 Pre-Depends: libbz2-1.0, libc6 (>= 2.15), liblzma5 (>= 5.2.2), libselinux1 (>= 2.3), zlib1g (>= 1:1.1.4)
 Depends: tar (>= 1.28-1)
 Suggests: apt, debsig-verify
 Breaks: acidbase (<= 1.4.5-4), amule (<< 2.3.1+git1a369e47-3), beep (<< 1.3-4), im (<< 1:151-4), libapt-pkg5.0 (<< 1.7~b), libdpkg-perl (<< 1.18.11), lsb-base (<< 10.2019031300), netselect (<< 0.3.ds1-27), pconsole (<< 1.0-12), phpgacl (<< 3.3.7-7.3), pure-ftpd (<< 1.0.43-1), systemtap (<< 2.8-1), terminatorx (<< 4.0.1-1), xvt (<= 2.1-20.1)
 Section: admin
 Priority: required
 Multi-Arch: foreign
 Homepage: https://wiki.debian.org/Teams/Dpkg
 Description: Debian package management system
  This package provides the low-level infrastructure for handling the
  installation and removal of Debian software packages.
  .
  For Debian package development tools, install dpkg-dev.

Take the dpkg deb package as an example to view the real content of the deb package

1. Use the ar command to unzip the deb package

root@virt-debian10:/tmp/test# ar -x ../dpkg_1.19.7_amd64.deb 
root@virt-debian10:/tmp/test# ls
control.tar.xz	data.tar.xz  debian-binary

2. View Debian binary file contents

root@virt-debian10:/tmp/test# cat ./debian-binary 
2.0

3. View control tar. XZ file content

root@virt-debian10:/tmp/test# tar -xvf ./control.tar.xz 
./
./conffiles
./control
./md5sums
./postinst
./postrm

3.1 contents of conf files file

root@virt-debian10:/tmp/test# cat conffiles 
/etc/alternatives/README
/etc/cron.daily/dpkg
/etc/dpkg/dpkg.cfg
/etc/logrotate.d/alternatives
/etc/logrotate.d/dpkg

The content of this file is a list of configuration files for the package.

3.2 control file content

root@virt-debian10:/tmp/test# cat control
Package: dpkg
Version: 1.19.7
Architecture: amd64
Essential: yes
Maintainer: Dpkg Developers <debian-dpkg@lists.debian.org>
Installed-Size: 6693
Pre-Depends: libbz2-1.0, libc6 (>= 2.15), liblzma5 (>= 5.2.2), libselinux1 (>= 2.3), zlib1g (>= 1:1.1.4)
Depends: tar (>= 1.28-1)
Suggests: apt, debsig-verify
Breaks: acidbase (<= 1.4.5-4), amule (<< 2.3.1+git1a369e47-3), beep (<< 1.3-4), im (<< 1:151-4), libapt-pkg5.0 (<< 1.7~b), libdpkg-perl (<< 1.18.11), lsb-base (<< 10.2019031300), netselect (<< 0.3.ds1-27), pconsole (<< 1.0-12), phpgacl (<< 3.3.7-7.3), pure-ftpd (<< 1.0.43-1), systemtap (<< 2.8-1), terminatorx (<< 4.0.1-1), xvt (<= 2.1-20.1)
Section: admin
Priority: required
Multi-Arch: foreign
Homepage: https://wiki.debian.org/Teams/Dpkg
Description: Debian package management system
 This package provides the low-level infrastructure for handling the
 installation and removal of Debian software packages.
 .
 For Debian package development tools, install dpkg-dev.

3. md5sums file content

root@virt-debian10:/tmp/test# cat md5sums 
708d64b33f8756aae3f1d0f7a6a2fb54  sbin/start-stop-daemon
9fd4b4d3254e3dcbc9a5ccab720c62f6  usr/bin/dpkg
ece2aef1292c9f4a25879b7cd6f2c4fb  usr/bin/dpkg-deb
5daa197d76b1628b363728adbc1cf6bc  usr/bin/dpkg-divert
5db5f84eef334d26845d752c6087c4a7  usr/bin/dpkg-maintscript-helper
0e68a2e82688114f42e6fc481d50e43c  usr/bin/dpkg-query
964a5c7c08ed40ec3ee86077240a6bc0  usr/bin/dpkg-split
2bb088d154310625d3a98da9a11f6914  usr/bin/dpkg-statoverride
7bce7162bb939bf55d6f27dfe2eff773  usr/bin/dpkg-trigger
01b64f08855d55ee2b1f395920d1ac83  usr/bin/update-alternatives
638083d212928607b198dfb2af90014a  usr/share/bug/dpkg
f5c2a9458457860e236b648010541d67  usr/share/doc/dpkg/AUTHORS
.........

The md5sum values of all installation files in the package are saved in this file.

4. Content of postinst file

root@virt-debian10:/tmp/test# cat ./postinst 
#!/bin/sh
# See deb-postinst(5).

set -e

# Create the database files if they don't already exist
create_database() {
    admindir=${DPKG_ADMINDIR:-/var/lib/dpkg}

    for file in diversions statoverride status; do
	if [ ! -f "$admindir/$file" ]; then
	    touch "$admindir/$file"
	fi
    done
}


# Create log file and set default permissions if possible
create_logfile() {
    logfile=$DPKG_ROOT/var/log/dpkg.log

    if [ ! -f "$logfile" ]; then
        touch "$logfile"
        chmod 644 "$logfile"
        chown root:root "$logfile" 2>/dev/null || chown 0:0 "$logfile"
    fi
}


case "$1" in
    configure)
	create_database
	create_logfile
	;;

    abort-upgrade|abort-deconfigure|abort-remove)
	;;

    *)
	echo "$0 called with unknown argument '$1'" 1>&2
	exit 1
	;;
esac


exit 0

This script is called by the deb-postinst command after the package is installed.

5. Contents of postrm file

root@virt-debian10:/tmp/test# cat ./postrm 
#!/bin/sh
# See deb-postrm(5).

set -e

# Remove log file when dpkg is purged
remove_logfile() {
    logdir=$DPKG_ROOT/var/log

    rm -f "$logdir"/dpkg.log "$logdir"/dpkg.log.* 2>/dev/null
    rm -f "$logdir"/alternatives.log "$logdir"/alternatives.log.* 2>/dev/null
}

case "$1" in
    remove)
	;;

    purge)
	remove_logfile
	;;

    upgrade)
	;;

    failed-upgrade|disappear|abort-install|abort-upgrade)
	;;


    *)
	echo "$0 called with unknown argument '$1'" 1>&2
	exit 1
	;;
esac


exit 0

This script is called by the deb-postrm command after the package is removed.

data.tar file content

root@virt-debian10:/tmp/test# tar -tvf ./data.tar.xz 
drwxr-xr-x root/root         0 2019-06-04 05:22 ./
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/alternatives/
-rw-r--r-- root/root       100 2019-06-04 05:22 ./etc/alternatives/README
drwxr-xr-x root/root         0 2019-06-04 05:22 ./etc/cron.daily/
-rwxr-xr-x root/root      1187 2019-04-19 10:14 ./etc/cron.daily/dpkg
.........

You can see data Tar stores all installation files in the package.

dpkg installation package process

Install the terminal output of dpkg package through dpkg command:

longyu@virt-debian10:/tmp$ sudo dpkg -i ./dpkg_1.19.7_amd64.deb 
(Reading database ... 69152 files and directories currently installed.)
Preparing to unpack ./dpkg_1.19.7_amd64.deb ...
Unpacking dpkg (1.19.7) over (1.19.7) ...
Setting up dpkg (1.19.7) ...
Processing triggers for man-db (2.8.5-2) ...

man dpkg gets the following information:

              Install the package. If --recursive or -R option is specified, package-file must refer to a directory instead.

              Installation consists of the following steps:

              1. Extract the control files of the new package.

              2. If another version of the same package was installed before the new installation, execute prerm script of the old package.

              3. Run preinst script, if provided by the package.

              4. Unpack the new files, and at the same time back up the old files, so that if something goes wrong, they can be restored.

              5.  If  another version of the same package was installed before the new installation, execute the postrm script of the old package. Note that this script
              is executed after the preinst script of the new package, because new files are written at the same time old files are removed.

              6. Configure the package. See --configure for detailed information about how this is done.

Summarize the steps of dpkg installation:

  1. Unzip the control file for the new package
  2. Scan the database to determine whether other versions of the new package have been installed. If yes, execute the prerm script of the old package
  3. When preinst exists in the control file of the new package, execute it
  4. Unzip the data of the new package Tar also backs up old files for error recovery
  5. If another version of the same package has been installed before this installation, execute the postrm script of the old package
  6. Configure the package, unpack the configuration files listed in conf files, and back up the old conf files for error recovery
  7. When postinst exists in the control file of the new package, execute it

Note: the postrm script of the old package is executed after the preinst script of the new package is executed because the new file is written while the old file is removed, that is, the execution of the preinst script of the new package is equivalent to the removal of the old package file

Topics: apt