1. Overview

Debian packages, often referred to as .deb packages, are a common way to distribute software on Debian and Debian-based Linux distributions such as Ubuntu and Linux Mint.

In this tutorial, we’ll see how to unpack, modify, and repack a .deb package to suit our specific needs or to fix problems.

2. Prerequisites

To follow this tutorial, we’ll need the dpkg-deb tool, which is usually installed by default on Debian-based distributions, as it’s a basic tool for handling packages. However, if it’s missing, we can install it using apt:

$ sudo apt install dpkg

We can download the .deb package we want to modify from an official or third-party repository. As a test case, we’ll modify the fonts-aenigma package provided by the Ubuntu jammy repository (compatible with Ubuntu 22.04 and Linux Mint 21):

$ mkdir deb
$ cd deb
$ wget -O 'fonts-aenigma-original.deb' \
'http://mirrors.kernel.org/ubuntu/pool/universe/f/fonts-aenigma/fonts-aenigma_0.0.20080511+dfsg-4_all.deb'

The same .deb is also available in other Ubuntu and Debian repositories.

This package installs 465 free fonts from Brian Kent. Our goal is to add another font to the package, the public domain Operation Napalm Font by GGBotNet:

$ wget https://get.fontspace.co/download/family/gx6w9/bf43cdbfcb454b8dbf5c56fd74d1a93a/operation-napalm-font.zip
[...]
$ 7z x operation-napalm-font.zip 
[...]
$ tree
.
├── fonts-aenigma-original.deb
├── info.txt
├── operation-napalm-font.zip
├── OperationNapalmItalic-1GgAv.ttf
└── OperationNapalm-nRBWO.ttf

As we can see from the last output, this font consists of two .ttf files.

As a side note, we used 7z v.16.02 with this particular .zip file because Debian’s unzip v.6.00 produces unreadable data.

3. Unpacking the .deb Package

To unpack a .deb package, we need to use the dpkg-deb command with the -R (–raw-extract) option, followed by the .deb filename and the target directory that dpkg-deb will create if it’s missing:

$ dpkg-deb -R fonts-aenigma-original.deb debdir

Let’s take a look at the unpacked contents:

$ tree debdir
debdir
├── DEBIAN
│   ├── control
│   └── md5sums
└── usr
    └── share
        ├── doc
        │   └── fonts-aenigma
        │       ├── 1015saturdaynight.txt
        │       ├── 36daysago.txt
                [...]
        └── fonts
            └── truetype
                └── aenigma
                    ├── 1015snr.ttf
                    ├── 1015sn.ttf
                    [...]

8 directories, 761 files

Let’s discuss this directory structure and contents:

  • DEBIAN/control → metadata and package control information, specifying details about the package, its dependencies, and other installation-related information
  • DEBIAN/md5sumsMD5 checksums for the files in the package, used to verify the integrity of the package during installation
  • usr/share/doc/fonts-aenigma → documentation for each font in a separate .txt file
  • usr/share/fonts/truetype → directory where TrueType fonts are typically stored on a Debian-based system
  • usr/share/fonts/truetype/aenigma → main directory for the Ænigma font family, containing all the TrueType (.ttf) font files

Other packages have more complex structures, including configuration scripts.

For a detailed view of package meta-information, we can consult The Debian Administrator’s Handbook.

4. Modifying Package Contents

Our changes should follow Debian conventions as well as any conventions adopted by the package maintainer.

4.1. Add the New Files

First, let’s move the two extra ttfs into the same folder where all the other ttfs are:

$ mv *.ttf ./debdir/usr/share/fonts/truetype/aenigma

Then, let’s do the same with the documentation. In this case, it’s the same for both ttfs:

cp info.txt ./debdir/usr/share/doc/fonts-aenigma/OperationNapalmItalic-1GgAv.txt
mv info.txt ./debdir/usr/share/doc/fonts-aenigma/OperationNapalm-nRBWO.txt

As an optional extra check, we can verify that the permissions of the added files are the same as those of all other files in the package.

4.2. DEBIAN/control

Before we go any further, let’s take a look at the contents of DEBIAN/control:

$ cat ./debdir/DEBIAN/control 
Package: fonts-aenigma
Version: 0.0.20080511+dfsg-4
Architecture: all
Maintainer: Ubuntu Developers <[email protected]>
Original-Maintainer: Debian Fonts Task Force <[email protected]>
Installed-Size: 23873
Conflicts: ttf-aenigma
Breaks: ttf-aenigma (<< 0.0.20080510.dfsg-3)
Replaces: ttf-aenigma (<< 0.0.20080510.dfsg-3)
Section: fonts
Priority: optional
Multi-Arch: foreign
Description: 465 free TrueType fonts by Brian Kent
 Fonts included in this package:
 .
  * 10.15 Saturday Night, R
  * 18 Holes
  [...]

All these elements in the DEBIAN/control file are described in detail in the Debian Policy Manual. In order for our distribution to understand that our custom package replaces the original one, we need to give it a different version number:

$ sed -i 's/Version: 0.0.20080511+dfsg-4/Version: 0.0.20080511+dfsg-4+custom1/' ./debdir/DEBIAN/control
$ cat ./debdir/DEBIAN/control | grep "Version: "
Version: 0.0.20080511+dfsg-4+custom1

Let’s take a closer look at the version numbers used by Debian:

We can increment the +custom part each time we make further modifications to our custom version to keep track of the changes.

4.3. DEBIAN/md5sums

The DEBIAN/md5sums file is formatted in a standard way:

$ cat ./debdir/DEBIAN/md5sums 
2209cebd6e707ff1abf24a7bd08861a3  usr/share/doc/fonts-aenigma/1015saturdaynight.txt
02117ed270377b6e4163e58697de615b  usr/share/doc/fonts-aenigma/36daysago.txt
15000f8ff84238312a20ed7f3c76d7c3  usr/share/doc/fonts-aenigma/3dlet.txt
[...]

Let’s rebuild it:

$ cd debdir/
$ find . -type f -not -path "./DEBIAN/*" -exec md5sum {} + | sort -k 2 | sed 's/\.\/\(.*\)/\1/' > DEBIAN/md5sums

This command regenerates a DEBIAN/md5sums identical to the original, except for the addition of the new files:

  • Finds all files in the current directory and its subdirectories, excluding the DEBIAN subdirectory
  • Runs the md5sum command on each file and prints the checksum and file path
  • Sorts the output by the second column, which is the file path, in alphabetical order
  • Removes the ./ prefix from each file path using sed
  • Redirects the final output to the DEBIAN/md5sums file

Now we’ve finished the changes.

Let’s note that if the original .deb package had included a Debian changelog, we’d have had to change that as well.

5. Repacking and Testing the Modified Package

We are ready to create the new package using the -b (–build) option of dpkg-deb:

$ cd ..
$ ls
debdir  fonts-aenigma-original.deb  operation-napalm-font.zip  tree.txt
$ dpkg-deb -b debdir fonts-aenigma-custom.deb
dpkg-deb: building package 'fonts-aenigma' in 'fonts-aenigma-custom.deb'.

Let’s use fc-list to verify that the Operation Napalm font we added to the original package isn’t currently installed:

$ fc-list | grep Napalm

Let’s install our custom package and repeat the font check:

$ sudo apt install ./fonts-aenigma-custom.deb
[...]
Note, selecting 'fonts-aenigma' instead of './fonts-aenigma-custom.deb'
The following packages will be upgraded:
  fonts-aenigma
1 upgraded, 0 newly installed, 0 to remove and 16 not upgraded.
[...]
Get:1 /home/francesco/deb/fonts-aenigma-custom.deb fonts-aenigma all 0.0.20080511+dfsg-4+custom1 [8.352 kB]
[...]
$ fc-list | grep Napalm
/usr/share/fonts/truetype/aenigma/OperationNapalm-nRBWO.ttf: Operation Napalm:style=Regular
/usr/share/fonts/truetype/aenigma/OperationNapalmItalic-1GgAv.ttf: Operation Napalm:style=Italic

apt correctly recognized our custom .deb package as an update to the original. Also, everything worked as expected because the two new ttfs were installed.

6. Conclusion

In this article, we discussed how to use the dpkg-deb tool, which is part of every Debian-based system, to unpack, edit, and repack the contents of a .deb package. It’s helpful for fixing problems, adding features, or customizing software on Debian-based systems.

In our example, we strictly followed Debian conventions to ensure the integrity and functionality of our custom package:

  • The new files respected the structure and contents of the original .deb package
  • The new version number in DEBIAN/control was recognized by Debian as a custom update
  • We created a new DEBIAN/md5sums file to reflect the changes

Finally, we installed our custom package and verified its functionality. Our changes had the desired effect, and the package interacted correctly with the system.