[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#518719: dpkg needs unpack support that does not run any maintainer scripts



Package: dpkg
Version: 1.14.25
Severity: normal

dpkg --unpack needs to be able to work without executing any maintainer scripts, just
extracting the data.tar.gz, decompressing the control.tar.gz, moving maintainer scripts
to the var/lib/dpkg/info/ directory, handling var/lib/dpkg/status and var/lib/dpkg/available
and leaving the status of the package as "Status: install ok unpacked"

This mode is particularly important for debootstrap usage when the archives are for a
different architecture to the host system. I've had to implement two versions of this
support, one in shell and one in perl, for Emdebian. The main objective is to achieve
a debootstrap that leaves an almost complete filesystem with every file in place and
only needing 'dpkg --configure -a' to be run on the actual machine.

Emdebian Grip has a particular need for this support, so that the debootstrap'd directory
can be packed into a .tar.gz *without* needing to carry large numbers of .deb packages in
var/cache/apt/archives/. It seems utterly pointless that 24Mb of .debs are needed merely so
that the maintainer scripts can be created and executed before removing all the .debs on 
a machine where file I/O can be slow and space for the extra 24Mb is not necessarily
available. It gets worse when such machines need to have more than a basic debootstrap
in the installation image, e.g. when the user needs to make a complete installation image
that includes a full XFCE GUI without any .debs in the tarball.

If the new mode could simply detect that the architecture of the .deb does not match the
architecture of the host system (i.e. the system outside the chroot), it could conceivably
do everything except executing any code/scripts installed by the package. This would also
require that the unpack mode would be closer to the extract support that is able to write
files to a nominated directory - i.e. running dpkg from outside the chroot and writing to
files in $PREFIX/var/lib/dpkg etc.

Requiring that a directory '$PREFIX' is specified and that the $PREFIX cannot be '/' should
minimise problems of this mode being used in a "normal" filesystem. As such, maybe an option
to dpkg -e would be more appropriate than a change to dpkg --unpack.

This is the test code (perl version) that adds to the functionality available with dpkg -e:
(I don't consider it fully debugged, it is merely here to show the steps that Emdebian
currently needs due to the lack of this functionality within dpkg itself. The final code
will be executed from the top level of what will become the chroot, but never from '/'
and will repeat over each archive in no particular order.)

#!/usr/bin/perl

# $dir will eventually hold a prefix that cannot be /
$dir="";
$cachedir="var/cache/apt/";
$libdir = "var/lib/apt/";     # lists
$etcdir = "etc/apt/";         # sources
$dpkgdir = "var/lib/dpkg/";   # state

&force_unpack;
exit 0;

sub force_unpack
{
	my %unpack=();
	$deb = "wget_1.11.4-2_armel.deb";
	{
		print "I: Extracting $deb...\n";
		system ("ar -p \"./${cachedir}archives/$deb\" data.tar.gz | zcat | tar -xf -");
		my $ver=`dpkg -f ./${cachedir}archives/$deb Version`;
		my $pkg=`dpkg -f ./${cachedir}archives/$deb Package`;
		chomp ($ver);
		chomp ($pkg);
		print "  -> Unpacking control data...\n";
		mkdir ("tmp/listing");
		system ("ar -p \"./${cachedir}archives/$deb\" data.tar.gz > tmp/listing/data.tar.gz");
		my $datatar = `tar -tzf tmp/listing/data.tar.gz`;
		my @lines = split("\n", $datatar);
		open (LIST, ">>${dpkgdir}info/${pkg}.list");
		foreach my $l (@lines)
		{
			chomp ($l);
			$l =~ s:^\.::;
			$l =~ s:^/$:/\.:;
			$l =~ s:/$::;
			print LIST "$l\n";
		}
		close (LIST);
		# this needs to use mktemp -d and only remove that dir.
		system ("rm -rf tmp/*");
		system ("dpkg -e ./${cachedir}archives/$deb tmp/");
		opendir (MAINT, "tmp");
		my @maint=grep(!m:\.\.?:, readdir (MAINT));
		closedir (MAINT);
		open (AVAIL, ">>${dpkgdir}available");
		open (STATUS, ">>${dpkgdir}status");
		foreach my $mscript (@maint)
		{
			rename "tmp/$mscript", "${dpkgdir}info/$pkg.$mscript";
			if ( $mscript eq "control" )
			{
				open (MSCRIPT, "${dpkgdir}info/$pkg.$mscript");
				my @scr=<MSCRIPT>;
				close (MSCRIPT);
				my @avail = grep(!/^$/, @scr);
				print AVAIL @avail;
				print STATUS @avail;
				print AVAIL "\n";
				print STATUS "Status: install ok unpacked\n";
				unlink ("${dpkgdir}info/$mscript");
			}
		}
		close (AVAIL);
		if ( -f "${dpkgdir}info/$pkg.conffiles")
		{
			print STATUS "Conffiles:\n";
			print "I: Processing $pkg.conffiles\n";
			open (CONF, "${dpkgdir}info/$pkg.conffiles");
			my @lines=<CONF>;
			close (CONF);
			foreach my $line (@lines)
			{
				chomp ($line);
				$md5=`md5sum $line | cut -d" " -f1`;
				print STATUS " $line $md5\n";
			}
		}
		print STATUS "\n";
		close (STATUS);
	}
}

The shell version is in the unpack_debootstrap routine in emrootfslib, part of the emdebian-rootfs
package in sid and squeeze and in empbuilderlib lenny.

http://packages.debian.org/squeeze/all/emdebian-rootfs/filelist


-- System Information:
Debian Release: squeeze/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.26-1-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8) (ignored: LC_ALL set to en_GB.UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages dpkg depends on:
ii  coreutils                     7.1-2      The GNU core utilities
ii  libc6                         2.9-4      GNU C Library: Shared libraries
ii  lzma                          4.43-14    Compression method of 7z format in

dpkg recommends no packages.

Versions of packages dpkg suggests:
ii  apt                           0.7.20.2   Advanced front-end for dpkg

-- no debconf information



Reply to: