200

I'm attempting to install Intel's OpenCL SDK but the DEB files are buggy conversions from RPM (see here for the curious). I need to edit the postinst script in the DEB they provide.

How can I take an existing DEB, extract the contents (including the control information), then later repackage the contents to make a new DEB? I will only edit files, no files will be added or removed.

Pang
  • 241
John Jumper
  • 2,105
  • the unpacking part can be done from midnight commander (apt install mc)— just press enter on a deb file – ccpizza Jul 14 '20 at 20:54

3 Answers3

325

The primary command to manipulate deb packages is dpkg-deb.

To unpack the package, create an empty directory and switch to it, then run dpkg-deb to extract its control information and the package files. Use dpkg-deb -b to rebuild the package.

mkdir tmp
dpkg-deb -R original.deb tmp
# edit DEBIAN/postinst
dpkg-deb -b tmp fixed.deb

Beware that unless your script is running as root, the files' permissions and ownership will be corrupted at the extraction stage. One way to avoid this is to run your script under fakeroot. Note that you need to run the whole sequence under fakeroot, not each dpkg-deb individually, since it's the fakeroot process that keeps the memory of the permissions of the files that can't be created as they are.

fakeroot sh -c '
  mkdir tmp
  dpkg-deb -R original.deb tmp
  # edit DEBIAN/postinst
  dpkg-deb -b tmp fixed.deb
'

Rather than mess with permissions, you can keep the data archive intact and modify only the control archive. dpkg-deb doesn't provide a way to do that. Fortunately, deb packges are in a standard format: they're ar archives. So you can use ar to extract the control archive, modify its files, and use ar again to replace the control archive by a new version.

mkdir tmp
cd tmp
ar p ../original.deb control.tar.gz | tar -xz
# edit postinst
cp ../original.deb ../fixed.deb
tar czf control.tar.gz *[!z]
ar r ../fixed.deb control.tar.gz

You should add a changelog entry and change the version number if you modify anything in the package. The infrastructure to manipulate Debian packages assumes that if two packages have the same name and version, they're the same package. Add a suffix to the debian_revision part at the end of the version number; for sorting reasons the suffix should start with ~, e.g. 1.2.3-4.1 becomes 1.2.3-4.1~johnjumper1.

Instead of using shell tools, you can use Emacs. The dpkg-dev-el package (which is its own upstream as this is a native Debian package) contains modes to edit .deb files and to edit Debian changelogs. Emacs can be used interactively or scripted.

  • 4
    You can also use the -e switch of fpm to change the control file: fpm -e -s deb -t deb ../old.deb. This will open the control file in your editor. – Artefacto Jun 30 '14 at 13:33
  • 1
    btw, fakeroot bash and try to issue commands will not work concerning ownership, and the ar method is incredbly fast for big deb files! – Aquarius Power Oct 06 '16 at 02:53
  • 2
    Thanks. This was useful. Using dpkg-deb -R the modes were kept and dpkg-deb -b reset the uid:gid of the extracted files to 0:0. Didn't need fakeroot (I imagine there might be issues if there were set{u,g}id files inside the archive but that wasn't the case in my situation. – Petr Skocik Aug 16 '18 at 10:52
  • 2
    @PSkocik Not just setxid files, also e.g. files and directories under /etc or /var that need to belong to a specific group. – Gilles 'SO- stop being evil' Aug 16 '18 at 19:33
  • Thanks for the great answer. Is there a way to ensure that the rebuilt package vs original package has the same md5sum? – AmaJayJB Oct 22 '19 at 13:35
  • @AmaJayJB In useful cases, the rebuilt package cannot have the same md5sum since it has different content. If you want to ensure that it has the same content in the special case when you don't make any edits, the code in my answer doesn't do that, you need to look into reproducible builds. – Gilles 'SO- stop being evil' Oct 22 '19 at 13:49
  • @PSkocik How did you confirm that the IDs have been reset? – stackprotector Nov 25 '20 at 06:15
  • Using the ar/tar method described, instead of dpkg-deb, can still result in ownership issues, and thus likely still requires using fakeroot. Lintian will warn: E: dummypackage: control-file-has-bad-owner md5sums user1/user1 != root/root E: dummypackage: control-file-has-bad-owner postinst user1/user1 != root/root E: dummypackage: control-file-has-bad-owner prerm user1/user1 != root/root – NickBroon Jun 04 '21 at 13:27
8

You can use fpm with the --after-install option to replace the postinst script, like this:

fpm -e --after-install ../DEBIAN/postinst.new -s deb -t deb ../old.deb
Juancho
  • 180
  • 1
  • 4
1

If you only want to extract files from a .deb file, 7-Zip is convenient. 7-Zip supports "ar" files for "unpacking only". (No need to rename the file; it opens *.deb as "ar" and shows "data.tar" inside.)

A876
  • 113
  • 2
    Welcome to the site, and thank you for your contribution. Please note that the OP specifically asked for "unpack DEB ... and repack DEB". Perhaps you can edit your post to address that subject, too. – AdminBee May 20 '20 at 06:31