09 February, 2009

Creating Debian Packages

I have to admit, one of the most appealing features of Debian is the ease of package management. While we've authored many tool suites to be used in analysis, field testing, or development I've yet to package them into a distribution package. While I've always wanted to, I've never taken the initiative to investigate how to do it. Today I'll be documenting my journey into authoring my first Debian distribution package.

Debian Packages
A package is a simple collection of files with instructions of what to do with them. While most often packages consist of executables, they may instead contain source code, window themes, or other file collections. Since I'm interested in maintaining executables I'll focus on the binary distribution package. I start my journey by issuing the command 'man deb'.

File Contents
All binary Debian packages consist of 3 basic files: 1 text file, and 2 compressed tarballs. You can examine the contents of a Debian package yourself by using the archive command to list the file contents. For example,


$ ar -t /var/cache/apt/archives/telnet_0.17-34_amd64.deb
debian-binary
control.tar.gz
data.tar.gz


You can examine the content of each file by extracting them from the archive, done by issuing the following command:

$ ar -x /var/cache/apt/archives/telnet_0.17-34_amd64.deb


debian-binary
This file contains the version number for the binary package, which should be 2.0.

control.tar.gz
This gzipped archive contains the control file, a postinst file, a prerm file and may optionally contain info about configuration files for the package and a MD5 checksums for the package. You can examine the contents of this archive by issuing:

$ tar -ztf ./control.tar.gz
./
./postinst
./prerm
./postrm
./md5sums
./control

The only mandatory file in this archive is the control file which contains the core control info for the package.
control
Issuing the command 'man deb-control' documents the contents of the mandatory and optional fields for the control file. The file consists of mandatory and optional fields. The mandatory fields are listed with brief descriptions of each.
Package: This value identifies the name of the package.
Version: This field identifies the version number. The use of a hyphen identifies the Debian revision number so the package author is restricted from using the hyphen the version number.
Maintainer: This should be defined in the format of full name followed by e-mail address 'Joe Bloggs '.
Description: This field should provide a brief description of the package as the first line. This should be followed by a more detailed package description where each line begins with a space.

data.tar.gz
This file contains the actual “payload” of the package. This means that it contains a filesystem with all the relevant files for the program that when installed will be placed in the appropriate spots on the destination systems file system.


$ tar -ztf ./data.tar.gz
./
./usr/
./usr/bin/
./usr/bin/telnet.netkit
./usr/share/
./usr/share/doc/
./usr/share/doc/telnet/
./usr/share/doc/telnet/README.telnet
./usr/share/doc/telnet/README.gz
./usr/share/doc/telnet/BUGS
./usr/share/doc/telnet/copyright
./usr/share/doc/telnet/changelog.gz
./usr/share/doc/telnet/README.telnet.old.gz
./usr/share/doc/telnet/changelog.Debian.gz
./usr/share/man/
./usr/share/man/man1/
./usr/share/man/man1/telnet.netkit.1.gz
./usr/share/menu/
./usr/share/menu/telnet


Building a Package
Now that you know what's in a Debian package building one is pretty simple. Start by creating a working directory where you'll store the contents of the package.

$ mkdir /var/tmp/deb

Next, create a subdirectory where the contents of the control file will be stored.

$ mkdir /var/tmp/deb/DEBIAN


Author the control file and locate it in the DEBIAN directory.

$ cat DEBIAN/control
Package: MyPackage
Version: 1.0
Maintainer: Fat Slow Kid
Description: A brief description.
A more thorough description with lines and charts
pictures and graphs with a 8x10 glossy photo
with descriptions and notations.


Next, create the directory structure of the binary file contents. In our example, we intend on installing a new script foo.sh in /usr/local/bin.

$ mkdir -p usr/local/bin


Create a foo.sh script in this directory, our contents are as follows:

$ cat usr/local/bin/foo.sh
#!/bin/sh

echo "running 'My Script'"

Lastly, move out of this working directory and build it with the Debian provided package utilities.

$ dpkg -b /var/tmp/deb MyPackage.deb


After this, a new MyPackage.deb file will exist in the present working directory. You can examine the intended installed files by issuing the command as follows:

$ dpkg --contents MyPackage.deb
drwxr-xr-x fsk/fsk 0 2009-02-08 23:11 ./
drwxr-xr-x fsk/fsk 0 2009-02-08 23:11 ./usr/
drwxr-xr-x fsk/fsk 0 2009-02-08 23:11 ./usr/local/
drwxr-xr-x fsk/fsk 0 2009-02-08 23:12 ./usr/local/bin/
-rwxr-xr-x fsk/fsk 38 2009-02-08 23:12 ./usr/local/bin/foo.sh


Installing this package will now recreate the file system structure starting at the destination systems root file directory. Namely, foo.sh will be located in /usr/local/bin when installed.

# dpkg -i MyPackage.deb
Selecting previously deselected package mypackage.
(Reading database ... 79280 files and directories currently installed.)
Unpacking mypackage (from MyPackage.deb) ...
Setting up mypackage (1.0) ...
xion:/home/fsk#
xion:/home/fsk# which foo.sh
/usr/local/bin/foo.sh
xion:/home/fsk# foo.sh
running 'My Script'
xion:/home/fsk#

Granted the removal procedures aren't defined, but you've got the start of your very own Debian package.

You've achieved your Debian package yellow-belt.

No comments: