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

testing config/preinst mods: one approach

I'm posting my approach to testing config/preinst scripts in hopes
that others may also find it helpful.

I'm sure I'm not alone in having sometimes run into a situation where
I wanted to try a change to a config or preinst script that is being
run at the time of package preconfiguration or installation.  Although
there are ways to do some of this by running scripts directly under
debconf, it's better to be able to be able to run scripts exactly as
they are run during normal installation.  For example, today I used
this approach to debug a problem with the preinst script in the
console-common package.  I did all the work in a base environment
after booting into single user mode for the first time after
installing a system with debian-installer beta4.

The approach here is to replace apt-extracttemplates (used to get
config and templates for preconfiguration) and dpkg-deb --control
(used to get control files during normal installation) with a version
that may optionally replace extracted files from pre-existing ones in
a special system directory.  Both scripts are designed to be
transparent in the case where no override files exist.

To use this approach, place these replacement apt-extracttemplates and
dpkg-deb scripts in your path before /usr/bin.  Extract the original
control files from a package and put them in a subdirectory of
override directory named identically to the .deb file in
/var/cache/apt/archives.  Then edit the modified files freely and
install as usual.

The scripts are configured with the override directory being
/root/control-overrides.  VERY IMPORTANT: Do not change the
control-overrides directory to a directory that is writable by a
non-trusted user (such as something in /tmp)!  These scripts do not
presently include any security checks.  They freely replace the
extracted control files with the ones in the override directory.  You
should trust your override directory as much as you trust your package
installation source.

Sample session:

mkdir /root/control-overrides
cd /root/control-overrides
apt-get --download-only install efax
/usr/bin/dpkg-deb --control \
  /var/cache/apt/archives/efax_1%3a0.9a-14_i386.deb \

Edit the control files in the
/root/control-overrides/efax_1%3a0.9a-14_i386.deb directory.

(efax chosen at random as a package with config scripts)

This approach relies on the fact that the package installation process
currently invokes apt-extracttemplates and dpkg-deb from the
installer's path.  An alternative approach would be to move the real
apt-extracttemplates and dpkg-deb out of the way (to *.real) and
replace them with these versions.  Then these versions could be
modified to invoke $0.real to do their real work.  This is more
invasive and not currently necessary, so I don't currently recommend
that approach.

Since the scripts are tiny, I'm attaching them directly to this
message.  I'd be interested any comments people may have on this
approach ranging from, "Why did you bother?  You could have just done
xyz instead," to constructive suggestions on improving this to just
stating that you do or do not find it to be a useful approach.  If you
think this is a bad approach, I'd be particularly interested in
knowing why.

Jay Berkenbilt <ejb@ql.org>
#!/usr/bin/env perl
# $Id: apt-extracttemplates,v 1.2 2004/05/11 17:18:50 ejb Exp $
# $Source: /home/ejb/source/debian/CVSroot/control-overrides/apt-extracttemplates,v $
# $Author: ejb $

BEGIN { $^W = 1; }
use strict;

# Don't want to depend upon File::Basename so this works on a base system.

my $whoami = ($0 =~ m,([^/\\]*)$,) ? $1 : $0;
#my $dirname = ($0 =~ m,(.*)[/\\][^/\\]+$,) ? $1 : ".";

my %pkgmap = ();
for (@ARGV)
    next unless m,^/,;
    my $archive = ($_ =~ m,([^/\\]*)$,) ? $1 : $_;
    $archive =~ m/^([^_]+)_/ or
	die "$whoami: can't get package/version name from archive $archive\n";
    my $pkg = $1;
    # Results undefined if user installs two version of the same
    # package at the same time.  That probably breaks anyway though.
    $pkgmap{$pkg} = $archive;

my $pid = open(P, "-|");
die "$whoami: fork failed: $!\n" unless defined $pid;
if ($pid == 0)
    exec "/usr/bin/apt-extracttemplates", @ARGV;
    die "$whoami: exec failed: $!\n";
while (<P>)
    my $orig = $_;
    my @fields = split(/ /, $_);
    my ($pkg, $version, $templates, $config) = @fields;
    my $archive = $pkgmap{$pkg} ||
	die "$whoami: can't get archive from $pkg\n";
    my $odir = "/root/control-overrides/$archive";
    if (-d $odir)
	foreach my $f (qw(templates config))
	    if (-f "$odir/$f")
		# Use cp rather than File::Copy::copy to preserve
		# permissions and to avoid depending upon File::Copy
		warn "\nUSING $odir/$f\n\n";
		system("cp -p $odir/$f " . eval "\$$f");
    print $orig;
# $Id: dpkg-deb,v 1.1 2004/05/11 17:01:34 ejb Exp $
# $Source: /home/ejb/source/debian/CVSroot/control-overrides/dpkg-deb,v $
# $Author: ejb $

if [ "$1" != "--control" ]; then
   exec /usr/bin/dpkg-deb ${1+"$@"}
   /usr/bin/dpkg-deb ${1+"$@"}
   archive=`basename "$2"`
   if [ "$archive" != "" -a -d "$dir" -a -d "$odir" ]; then
      rm $dir/*
      echo 1>&2 ""
      echo 1>&2 "USING $odir/$f"
      echo 1>&2 ""
      cp -p $odir/* $dir/

Reply to: