Debian Cheat Sheet

Carlo Wood, March 2007

Table of contents

Finding things

If you want to find something, there are several classes of objects that you can start with. Click on the link describing what you already have.

Packages

When looking for information, you normally first want to find the package name. Here is how to list all packages that are installed:

dpkg -l
The package names are listed in the second column. The third column is the version, the fourth and last column a short description. The meaning of the first column is printed in the first three lines of the output. If the package name is already known, one can get this information for a single package by running:
dpkg -l name

Package files

These are the .deb files that contain a package. The first part of the file name up till the first underscore is usually the package name.

Information about a package file can be obtained with the command:

dpkg --info package.deb

This should extract the name of this package:

dpkg --info package.deb | grep '^Source: ' | sed -e 's/Source: //'

Sources

Sources are normally not installed. You can only install them if you know the package name. When installing the sources of a debian package, a package ending on .dsc (description) is downloaded along with an original tar ball and a debian specific diff (compressed). The .dsc will contain the name of the package, both, in its filename as well as content (after the Source: keyword).

Installed files

If you have a file /path/filename installed, and you want to know what package it belongs to (if any), then issue the following command:

dpkg -S /path/filename

This will print name: /path/filename.

Actually it's dpkg -S filename-search-pattern, where filename-search-pattern can contain the usual shell wildchars. The command can therefore also used to search in a fuzzy way for packages that have files installed matching the given pattern. It does however not find/return extra files created by maintainer scripts, nor will it list alternatives. You can therefore not conclude that it is safe to delete a file if dpkg -S doesn't return any packages.

Note that it's a capitial -S, a lower case -s returns status information for a package name.

Other files

In order to find packages that contain file patterns that you do not have installed, you need to install apt-file: apt-get install apt-file.

Like for apt-get you need to regularly synchronize the apt-file database by running,

sudo apt-file update

Then, search for the filename using,

apt-file search pattern

will give you a list of packages containing files matching pattern.

Some keyword

apt-file search is somewhat equivalent to

apt-cache search regexp

They use the same data from the repositories listed in your sources.list file (although each uses it's own cache and needs to be seperately synchronized with apt-file update and apt-get update respectively.)

The big difference is this: apt-file search matches against the filenames of packages, while apt-cache search matches against package name, filenames and the long description of packages. The second has an option to limit what is matched against though: apt-cache --names-only search only matches against the package names. Only apt-file has options to influence how the pattern is interpreted: --regexp (-x) treats the pattern as a regular expression, like apt-cache, while --ignore-case (-i) does a case insensitive search. Finally, --fixed-string (-F) interprets the given string as the trailing fixed string of the filename (thus, contrary what apt-file's man page says, the search pattern is still expanded with generic characters at pattern’s start).

Queries

Now you have the package name, you can query the package database about it.

Contents

To print a list of all installed files (again excluding extra files as generated by maintainer script or alternatives), issue the command:

dpkg -L name

You can also use this command to find out if a package with that exact name is installed at all.

Or, if you have a package file that isn't installed yet, you can list it's contents with

dpkg --contents package.deb

Version / Short description

To print the version and a short description of of an installed package, type

dpkg -l name

Everything

More information about an installed package can be obtained with the status command:

dpkg -s name

Or, if the package isn't installed yet

dpkg --info package.deb

Customizing packages

Getting the source

To work with Debian source packages, do as root:

apt-get install build-essential fakeroot devscripts debhelper docbook-to-man

Often, a single source package generates multiple binary packages. In order to find the name of the source that belongs to some package, use dpkg -s. For example,

dpkg -s name | grep '^Source:' | sed -e 's/Source: //'

should print the source name of the package.

This name can then be used to download the sources with the command:

apt-get source name

This command downloads the original source tar-ball (.orig.tar.gz), a file with some decriptive info (.dsc) and a (compressed) diff (.diff.gz). The tar-ball is unpacked and the diff is applied.

If for some reason you want to redo this later again, you can use the commands:

dpkg-source -x name_VERSION.dsc

or, manually (I'll remove this once I know the above addition really works ;)

tar xzf name_VERSION.orig.tar.gz
mv name_VERSION.orig name_VERSION
cd name_VERSION
gzip -dc ../name_VERSION.diff.gz | patch -p1 -s
chmod +x debian/rules

Building from source

In order to build a package, execute once as root:

apt-get build-dep name

This will install packages that are needed to build this package.

A source tree which supports debian has a debian directory in the root of the source tree. This directory contains a script called rules, which is actually a Makefile, but is executed as a script. There are several targets, including configure, build, install and clean. Normally you don't want to install the package onto your real system of course! Never run debian/rules as root therefore, or bad things might happen.

While testing changes that you make to the code, you can (re)build the package with the command:

DEB_HOST_MULTIARCH="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" debian/rules build-arch

Of course, you can pass -j <n> to debian/rules, which is actually a self-executing Makefile, to do parallel builds, or use parallel=<n> in DEB_BUILD_OPTIONS.

If you want to debug this code, you should first set the following environment variable:

export DEB_BUILD_OPTIONS="nostrip noopt debug parallel=8"

Which is a space separated list of compile options. This will prevent the binaries to be stripped and compile without optimization.

If you want to build a binary package, the package has to be 'installed'. The correct way to do this is by using the utility fakeroot, which fakes an install, so that you can build a binary package as non-root and without really installing it. The following command should build a binary package:

fakeroot debian/rules binary

The binary target is yet another Makefile target that will first execute a configure, build and install if still necessary. If you already did build the package, then only an install would first be done, etc.

This will have created a file ../somename_VERSION_ARCH.deb, where ARCH is for example i386. More than one binary package can have been created.

Creating a patch

If you want to change the source code, you will need to make a diff of the changes that you made, otherwise it is not possible to create a debian package. In order to create this diff, you need to keep a copy of the original source tree, with all debian patches already applied. Therefore, before you make any changes, make a backup copy of the source tree using the following commands:

cd $NAME-$VERSION
fakeroot debian/rules clean
dpatch apply-all
cp -pr ../$NAME-$VERSION ../$NAME-$VERSION-origdeb

Next, you can make changes and test the code by building it with debian/rules build. Once you are satisfied, create a new patch as follows:

cd ..
diff -rc $NAME-$VERSION-origdeb $NAME-$VERSION > patchname.diff

Check if the diff looks sane (ie, doesn't contain unexpected hunks)

Adding a patch to a debian package

Add the patch to the source tree with (create the directory debian/patches if it does not already exist):

cd $NAME-$VERSION
dpatch patch-template -p "99_some_patch" "Description of patch" < ../patchname.diff > debian/patches/99_patchname.dpatch
chmod +x debian/patches/99_patchname.dpatch

Where the '99' should be chosen such that all your patches are applied in the correct order and after the original debian patches. Use dpatch list-all to obtain a list

Edit debian/patches/99_patchname.dpatch to fix your name and email address.

Edit debian/patches/00list (create it if it does not already exist) and add "99_patchname" to the list of patches.

Test if the patch applies with:

dpatch deapply-all
dpatch apply-all

Finally, add a changelog entry to debian/changelog. This is crucial since it is the only way to change the version of the package, reflecting that you made changes to it.

cd $NAME-$VERSION
dch -i

The format of the changelog entry is:

name (VERSION) unstable; urgency=low

  * Comments.
 
 -- Your Name <your@email> DATE

dch -i makes an 'official' increment to the VERSION, but that is probably not what you want. The VERSION that you use should be larger than the current version. For example, if the current version is 2.6.4-2, then you could change it into 2.6.4-2foo, or just add your initials. Do not add a hypen or dot. If uncertain, you can check if the version is considered larger with the command:
dpkg --compare-versions 2.6.4-2 lt 2.6.4-2foo && echo OK.

Now you can (re)build your debian package with fakeroot debian/rules binary.

Creating a source package

Because you made changes, you now also might want to create a source package (the original .diff.gz and .dsc files).

The command to do this is:

fakeroot debian/rules clean
cd ..
dpkg-source -b name-VERSION

Setting up a repository

In order to be able to continue to use apt-get update and apt-get upgrade painlessly, you should set up your own local repository with any packages that you made changes to.

For example, I made changes to the xchat package, and created a directory /usr/src/dists/xchat in which I downloaded the sources, and later created the .deb files. For example, an ls inside the directory /usr/src/dists/xchat on my machine shows:

/usr/src/dists/xchat>ls
overridefile  xchat_2.6.8-0.3.diff.gz     xchat_2.6.8-0.3run_i386.deb
Packages.gz   xchat_2.6.8-0.3.dsc         xchat_2.6.8.orig.tar.gz
Release       xchat_2.6.8-0.3run.diff.gz  xchat-common_2.6.8-0.3run_all.deb
xchat-2.6.8/  xchat_2.6.8-0.3run.dsc

We recognize the following files:

The files that were downloaded with the command apt-get source xchat:

The files generated by fakeroot debian/rules binary:

New source package files generated with dpkg-source -b xchat-2.6.8:

Finally, we see three files that are needed to turn this directory into a local repository:

The contents of overridefile are:

xchat optional net Carlo Wood <carlo@alinoe.com>
xchat-common optional net Carlo Wood <carlo@alinoe.com>

Of course, replace "Carlo Wood <carlo@alinoe.com>" with your own name and email address. This string will be used for the 'Maintainer' of packages. The 'optional' and 'net' strings are respectively the 'Priority:' and 'Section:' status fields (dpkg -s or dpkg -info), for example use

dpkg --info xchat_2.6.8-0.3run_i386.deb | egrep '(Priority|Section):'
to print the original values.

The Packages.gz file is generated from that with the following command:

dpkg-scanpackages . overridefile | gzip > Packages.gz

The Release file contains:

Origin: Run
Label: Local repository
Suite: testing
Architectures: i386
Components: contrib
Description: Customized packages by Carlo Wood
MD5Sum:
 f71c05625f8690c2f9cae621dfbe0116 900 ./Packages.gz

There are several things important here: The Suite: must match whatever suite you are using (stable, testing, unstable). The Origin: must be a unique string that we will use in /etc/apt/preferences to pin this package to this repository: that way you won't accidently "upgrade" the package, losing your changes. The md5sum can be calculated with the command:

md5sum Packages.gz

The size (900 above) can be retrieved with ls -l Packages.gz.

Optionally, one can add more or other sums, using sha1sum (with label SHA1:), and/or using sha256sum (with label SHA256:). It is also possible to add an uncompressed Packages file. For example,

MD5Sum:
 70c80c40007f69ce04b9697bbe0ed3bd 1818 ./Packages
 f71c05625f8690c2f9cae621dfbe0116  900 ./Packages.gz
SHA1:
 44e38fde666e6d2093b8ae523e8bba17fa19549c 1818 ./Packages
 003e795f97c21b35da573f20c86f325cceabf29a  900 ./Packages.gz
SHA256:
 b4fef40d5d901a0b310ffcc1a8930e2d994d5c87b71926365061e3d3399616ed 1818 ./Packages
 03825be1af8a4f1b552928b190aaae3408af6601c2fb178245e823f46ef50b71  900 ./Packages.gz

Next, tell apt where the new repository is. Add like the following to your /etc/apt/sources.list file:

# Packages with local changes are listed here.
deb file:///usr/src/dists/xchat ./

where you have to replace the directory with the path that you used.

The final step needed is setting up the pinning, see the next paragraph. After that, you can simply run sudo apt-get update and apt-get install xchat, or whatever package you created.

Pinning the packages of your local repository

In order to give priority to the packages in your local repository, create a file /etc/apt/preferences with the following content:

Package: *
Pin: release o=Run
Pin-Priority: 1000

where you have to replace the string "Run" with whatever you used as Origin: in your Release file.

Important: If you have a line in your /etc/apt/apt.conf file like: APT::Default-Release "testing";, then delete that line from /etc/apt/apt.conf! The effect of that line is exactly the same as adding a pin with Pin-Priority of 990 for a release archive "testing" at the top of your /etc/apt/preferences file, completely destroying the functionality of how pinning works because you don't want that at the top of your preferences file. The reason for that is this: Packages are matched top down, and the first match found is used for a particular repository (independent of the priority, and independent of any existing version Pins (see below)) to set it's priority. Thus, if you put a package with the name 'xchat' in your local repository, and there is also a package with that name in the "testing" repository, then the first match would be for the version in the "testing" repository, setting the priority of your local repository to 990, regardless. If you use:

Package: *
Pin: release a=testing
Pin-Priority: 990

Package: *
Pin: release o=Run
Pin-Priority: 1000

in your /etc/apt/preferences file, or the equivalent of APT::Default-Release "testing"; in your /etc/apt/apt.conf file, then the output of apt-cache policy xchat would be:

xchat-common:
  Installed: (none)
  Candidate: 2.6.8-0.3run
  Version table:
     2.6.8-0.3run 0
        990 file: ./ Packages
     2.6.8-0.3 0
        990 http://ftp.nluug.nl testing/main Packages
        500 http://ftp.nluug.nl unstable/main Packages

where our local repository has a priority of 990 as you see. See below for more explanations on how to interpret the output of apt-get policy.

We want our local repository to overrule, therefore it needs to be at the top instead:

Package: *
Pin: release o=Run
Pin-Priority: 1000

Package: *
Pin: release a=testing
Pin-Priority: 990

As above, replace "Run", and replace "testing" with whatever you have installed as Suite!

Pinning errata

The documentation of pinning is a bit incomplete and unclear. I had to debug the actual source code of apt in order to find out how it really worked. Hopefully, this document will answer questions of many others who are trying to do something with pinning. I am assuming that you already read all other documentation on pinning before you read this.

The final conclusion has to be that not only the official documentation of apt, in regard to pinning, sucks— but the whole design and algorithm that determines the candidate version is borked. It is counter-intuitive, ambiguous and not as flexible as it could be.

If this documentation helped you, then I'd appreciate it if you dropped me a mail: carlo@alinoe.com.