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

Re: Bug#319515: new kernel-package creates ridiculous symlinks in /boot



On Sat, Jul 23, 2005 at 03:03:51AM -0500, Manoj Srivastava wrote:
>         I can't reproduce this problem. Can you send me the kernel
>  image postinst?  This could be something that is ppc specific, I
>  think.

Postinst is attached. Sorry about the double submission. I'm not quite
sure how that happened...

-- 
Itai

Itai Seggev, University of Chicago, Department of Physics

In 1997 a group of programmers started writing a desktop environment
to fix a travesty they didn't create.  Their program promptly found
its way onto un*x systems everywhere. Today, still opposed by a
software monopolist, they survive as soldiers of fortune.  If you share
their vision, if you know you can help, and if you can connect to
internet, maybe you can join... the K-Team.
#! /usr/bin/perl
#                              -*- Mode: Cperl -*-
# debian.postinst ---
# Author           : Manoj Srivastava ( srivasta@pilgrim.umass.edu )
# Created On       : Sat Apr 27 05:55:26 1996
# Created On Node  : melkor.pilgrim.umass.edu
# Last Modified By : Manoj Srivastava
# Last Modified On : Tue Jun 21 14:28:22 2005
# Last Machine Used: glaurung.internal.golden-gryphon.com
# Update Count     : 295
# Status           : Unknown, Use with caution!
# HISTORY          :
# Description      :
#
#    $Id: image.postinst,v 1.125 2003/10/07 16:24:20 srivasta Exp $
#

#
#use strict; #for debugging
use Cwd 'abs_path';

$|=1;

# Predefined values:
my $version           = "2.6.12grvisitor1";
my $link_in_boot      = "";   # Should be empty, mostly
my $no_symlink        = "";   # Should be empty, mostly
my $reverse_symlink   = "";   # Should be empty, mostly
my $do_symlink        = "Yes";  # target machine defined
my $do_boot_enable    = "Yes";  # target machine defined
my $do_bootfloppy     = "Yes";  # target machine defined
my $do_bootloader     = "Yes";  # target machine defined
my $move_image        = '';     # target machine defined
my $kimage            = "vmlinux";   # Should be empty, mostly
my $loader            = "yaboot"; # lilo, silo, quik, palo, vmelilo, nettrom, arcboot or delo
my $image_dir         = "/boot";        # where the image is located
my $clobber_modules   = '';          # target machine defined
my $relative_links    = "";          # target machine defined
my $initrd            = "YES";        # initrd kernel
my $mkimage           = "";   # command to generate the initrd image
my $do_initrd         = '';     # Normally we do not
my $warn_initrd       = 'YES';  # Normally we do
my $use_hard_links    = ''; # hardlinks do not work across fs boundaries
my $postinst_hook     = '';          #Normally we do not
my $postrm_hook       = '';          #Normally we do not
my $preinst_hook      = '';          #Normally we do not
my $prerm_hook        = '';          #Normally we do not
my $minimal_swap      = '';          # Do not swap symlinks
my $ignore_depmod_err = '';          # normally we do not
my $relink_src_link   = 'YES'; # There is no harm in checking the link
my $relink_build_link = 'YES'; # There is no harm in checking the link
my $force_build_link  = '';    # There is no harm in checking the link
my $official_image    = "";  # only true for official images
my $arch              = "powerpc"; #  should be same as dpkg --print-installation-architecture
my $kernel_arch       = "";
my $ramdisk           = '/usr/sbin/mkinitrd';  # Tool to create initial ram fs.

my $package_name    = "kernel-image-$version";

my $Loader          = "NoLOADER"; #
$Loader             = "LILO"     if $loader =~ /^lilo/io;
$Loader             = "SILO"     if $loader =~ /^silo/io;
$Loader             = "QUIK"     if $loader =~ /^quik/io;
$Loader             = "yaboot"   if $loader =~ /^yaboot/io;
$Loader             = "PALO"     if $loader =~ /^palo/io;
$Loader             = "NETTROM"  if $loader =~ /^nettrom/io;
$Loader             = "VMELILO"  if $loader =~ /^vmelilo/io;
$Loader             = "ZIPL"     if $loader =~ /^zipl/io;
$Loader             = "ELILO"    if $loader =~ /^elilo/io;
$Loader             = "ARCBOOT"  if $loader =~ /^arcboot/io;
$Loader             = "DELO"     if $loader =~ /^delo/io;

# This should not point to /tmp, because of security risks.
my $temp_file_name = "/var/log/$loader" . "_log.$$";

#known variables
my @boilerplate     = ();
my @silotemplate    = ();
my @quiktemplate    = ();
my @palotemplate    = ();
my @vmelilotemplate = ();
my @zipltemplate    = ();
my @arcboottemplate = ();
my @delotemplate    = ();
my $bootdevice      = '';
my $rootdevice      = '';
my $rootdisk        = '';
my $rootpartition   = '';
my $image_dest      = "/";
my $realimageloc    = "/$image_dir/";
my $have_conffile   = "";
my $silent_modules  = '';
my $silent_loader   = '';
my $modules_base    = '/lib/modules';
my $CONF_LOC        = '/etc/kernel-img.conf';

# Ignore all invocations except when called on to configure.
exit 0 unless $ARGV[0] =~ /configure/;

my $DEBUG = 0;

# Do some preliminary sanity checks here to ensure we actually have an
# valid image dir
chdir('/')           or die "could not chdir to /:$!\n";
die "Internal Error: ($image_dir) is not a directory!\n"
  unless -d $image_dir;

# remove multiple leading slashes; make sure there is at least one.
$realimageloc  =~ s|^/*|/|o;
$realimageloc  =~ s|/+|/|o;
die "Internal Error: ($realimageloc) is not a directory!\n"
  unless -d $realimageloc;

if (-r "$CONF_LOC" && -f "$CONF_LOC"  ) {
  if (open(CONF, "$CONF_LOC")) {
    while (<CONF>) {
      chomp;
      s/\#.*$//g;
      next if /^\s*$/;

      $do_symlink      = "" if /do_symlinks\s*=\s*(no|false|0)\s*$/ig;
      $no_symlink      = "" if /no_symlinks\s*=\s*(no|false|0)\s*$/ig;
      $reverse_symlink = "" if /reverse_symlink\s*=\s*(no|false|0)\s*$/ig;
      $link_in_boot    = "" if /image_in_boot\s*=\s*(no|false|0)\s*$/ig;
      $link_in_boot    = "" if /link_in_boot\s*=\s*(no|false|0)\s*$/ig;
      $move_image      = "" if /move_image\s*=\s*(no|false|0)\s*$/ig;
      $clobber_modules = '' if /clobber_modules\s*=\s*(no|false|0)\s*$/ig;
      $do_boot_enable  = '' if /do_boot_enable\s*=\s*(no|false|0)\s*$/ig;
      $do_bootfloppy   = '' if /do_bootfloppy\s*=\s*(no|false|0)\s*$/ig;
      $relative_links  = '' if /relative_links \s*=\s*(no|false|0)\s*$/ig;
      $do_bootloader   = '' if /do_bootloader\s*=\s*(no|false|0)\s*$/ig;
      $do_initrd       = '' if /do_initrd\s*=\s*(no|false|0)\s*$/ig;
      $warn_initrd     = '' if /warn_initrd\s*=\s*(no|false|0)\s*$/ig;
      $use_hard_links  = '' if /use_hard_links\s*=\s*(no|false|0)\s*$/ig;
      $silent_modules  = '' if /silent_modules\s*=\s*(no|false|0)\s*$/ig;
      $silent_loader   = '' if /silent_loader\s*=\s*(no|false|0)\s*$/ig;
      $minimal_swap    = '' if /minimal_swap\s*=\s*(no|false|0)\s*$/ig;
      $ignore_depmod_err = '' if /ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig;
      $relink_src_link   = '' if /relink_src_link\s*=\s*(no|false|0)\s*$/ig;
      $relink_build_link = '' if /relink_build_link\s*=\s*(no|false|0)\s*$/ig;
      $force_build_link  = '' if /force_build_link\s*=\s*(no|false|0)\s*$/ig;

      $do_symlink      = "Yes" if /do_symlinks\s*=\s*(yes|true|1)\s*$/ig;
      $no_symlink      = "Yes" if /no_symlinks\s*=\s*(yes|true|1)\s*$/ig;
      $reverse_symlink = "Yes" if /reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig;
      $link_in_boot    = "Yes" if /image_in_boot\s*=\s*(yes|true|1)\s*$/ig;
      $link_in_boot    = "Yes" if /link_in_boot\s*=\s*(yes|true|1)\s*$/ig;
      $move_image      = "Yes" if /move_image\s*=\s*(yes|true|1)\s*$/ig;
      $clobber_modules = "Yes" if /clobber_modules\s*=\s*(yes|true|1)\s*$/ig;
      $do_boot_enable  = "Yes" if /do_boot_enable\s*=\s*(yes|true|1)\s*$/ig;
      $do_bootfloppy   = "Yes" if /do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig;
      $do_bootloader   = "Yes" if /do_bootloader\s*=\s*(yes|true|1)\s*$/ig;
      $relative_links  = "Yes" if /relative_links\s*=\s*(yes|true|1)\s*$/ig;
      $do_initrd       = "Yes" if /do_initrd\s*=\s*(yes|true|1)\s*$/ig;
      $warn_initrd     = "Yes" if /warn_initrd\s*=\s*(yes|true|1)\s*$/ig;
      $use_hard_links  = "Yes" if /use_hard_links\s*=\s*(yes|true|1)\s*$/ig;
      $silent_modules  = 'Yes' if /silent_modules\s*=\s*(yes|true|1)\s*$/ig;
      $silent_loader   = 'Yes' if /silent_loader\s*=\s*(yes|true|1)\s*$/ig;
      $minimal_swap    = 'Yes' if /minimal_swap\s*=\s*(yes|true|1)\s*$/ig;
      $ignore_depmod_err = 'Yes' if /ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig;
      $relink_src_link   = 'Yes' if /relink_src_link\s*=\s*(yes|true|1)\s*$/ig;
      $relink_build_link = 'Yes' if /relink_build_link\s*=\s*(yes|true|1)\s*$/ig;
      $force_build_link = 'Yes' if /force_build_link\s*=\s*(yes|true|1)\s*$/ig;

      $image_dest      = "$1"  if /image_dest\s*=\s*(\S+)/ig;
      $postinst_hook   = "$1"  if /postinst_hook\s*=\s*(\S+)/ig;
      $postrm_hook     = "$1"  if /postrm_hook\s*=\s*(\S+)/ig;
      $preinst_hook    = "$1"  if /preinst_hook\s*=\s*(\S+)/ig;
      $prerm_hook      = "$1"  if /prerm_hook\s*=\s*(\S+)/ig;
      $mkimage         = "$1"  if /mkimage\s*=\s*(.+)$/ig;
      $ramdisk         = "$1"  if /ramdisk\s*=\s*(\S+)/ig;
    }
    close CONF;
    $have_conffile = "Yes";
  }
}



# For some versions of kernel-package, we had this warning in the
# postinst, but the rules did not really interpolate the value in.
# Here is a sanity check.
my $pattern = "=" . "I";
$initrd=~ s/^$pattern$//;

# no floppy disk support available for m68k VME, and it is not very useful
# to make a boot floppy on PowerMac hardware at all.
$do_bootfloppy = "" if $loader =~ /^vmelilo/io;
$do_bootfloppy = "" if $loader =~ /^quik/io;
$do_bootfloppy = "" if $loader =~ /^yaboot/io;
$do_bootfloppy = "" if $loader =~ /^noloader/io;
$do_bootfloppy = "" if $loader =~ /^zipl/io;
$do_bootfloppy = "" if $loader =~ /^elilo/io;
$do_bootfloppy = "" if $loader =~ /^arcboot/io;
$do_bootfloppy = "" if $loader =~ /^delo/io;

# We can't have boot floppies for initrd kernels
$do_bootfloppy = "" if $initrd;

if ($link_in_boot) {
  $image_dest = "/$image_dir/";
  $image_dest =~ s|^/*|/|o;
}

$image_dest = "$image_dest/";
$image_dest =~ s|/+$|/|o;

if (! -d "$image_dest") {
  die "Expected Image Destination dir ($image_dest) to be a valid directory!\n";
}

# sanity
if (!($do_bootfloppy || $do_bootloader)) {
  $do_boot_enable = '';
}
if ($do_symlink && $no_symlink) {
  warn "Both do_symlinks and no_symlinks options enabled; disabling no_symlinks\n";
  $no_symlink = 0;
}

# Official powerpc images may silently upgrade
if ($official_image =~ /^\s*YES\s*$/o && $arch =~ m/powerpc/) {
  $silent_modules = 'Yes';
}



# most of our work is done in $image_dest (nominally /)
chdir("$image_dest") or die "could not chdir to $image_dest:$!\n";

# Paranoid check to make sure that the correct value is put in there
if    (! $kimage)                 { $kimage = "vmlinuz"; } # Hmm. empty
elsif ($kimage =~ m/^b?zImage$/o) { $kimage = "vmlinuz"; } # these produce vmlinuz
elsif ($kimage =~ m/^[iI]mage$/o) { my $nop = $kimage;   }
elsif ($kimage =~ m/^vmlinux$/o)  { my $nop = $kimage;   }
else                              { $kimage = "vmlinuz"; } # Default

$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch;


die "Internal Error: Could not find image (" . $realimageloc
  . "$kimage-$version)\n" unless -e $realimageloc
  . "$kimage-$version";

# search for the boot loader in the path
my $loader_exec;
($loader_exec = $loader)  =~ s|.*/||;
my ($loaderloc) = grep -x, map "$_/$loader_exec",
  map { length($_) ? $_ : "." }  split /:/, $ENV{PATH};


######################################################################
## Fix the build link
######################################################################
sub fix_build_link {
  return unless -d "$modules_base/$version";
  # if we saved a build link in preinst, restore the link
  if (! -e "$modules_base/$version/build" && 
      -l "$modules_base/$version/build.save" ) {
    rename("$modules_base/$version/build.save", "$modules_base/$version/build") ||
      die "failed to move $modules_base/$version/build:$!";
  }
  if ($relink_build_link || $force_build_link) {
    my $build_target;
    my $real_target = '';
    if (-l "$modules_base/$version/build") {
      $build_target = readlink "$modules_base/$version/build";
    } else {
      return;
    }
    # Determine what the real file name is, and test that for existence
    $real_target = abs_path($build_target) if defined($build_target);
    if (!defined($build_target) || ! -d "$real_target") { # Danglink link
      warn qq(
 Hmm. There is a symbolic link $modules_base/$version/build
 However, I can not read it: $!
 Therefore, I am deleting $modules_base/$version/build\n
);
      my $num = unlink "$modules_base/$version/build";
      if ($num != 1) {
        warn "error unlinking $modules_base/$version/build";
      } else {
        if ($force_build_link || -d "/usr/src/kernel-headers-$version") {
          my $result = symlink ("/usr/src/kernel-headers-$version",
                                "$modules_base/$version/build");
          if (! $result) {
            warn "Could not link /usr/src/kernel-headers-$version to $modules_base/$version/build:$!"
          }
        }
      }
    }
  }
}

if ($relink_build_link || $force_build_link) {
  &fix_build_link();
}
######################################################################
## Fix the source link
######################################################################
sub fix_source_link {
  return unless -d "$modules_base/$version";
  if ($relink_src_link) {
    my $source_target;
    my $real_target = '';

    if (-l "$modules_base/$version/source") {
      $source_target = readlink "$modules_base/$version/source";
    } else {
      return;
    }
    # Determine what the real file name is, and test that for existence
    $real_target = abs_path($source_target) if defined($source_target);
    if (!defined($source_target) || ! -d "$real_target") { # Danglink link
      warn qq(
 Hmm. The package shipped with a symbolic link $modules_base/$version/source
 However, I can not read it: $!
 Therefore, I am deleting $modules_base/$version/source\n
);
      my $num = unlink "$modules_base/$version/source";
      if ($num != 1) {
        warn "error unlinking $modules_base/$version/source";
      }
    }
  }
}

if ($relink_src_link) {
  &fix_source_link();
}
######################################################################
######################################################################
###########        Test whether a relative symlinkwould be OK #######
######################################################################
######################################################################
sub test_relative {
  my %params = @_;
  my $cwd;

  die "Internal Error: Missing Required paramater 'Old Dir' "
    unless $params{'Old Dir'};
  die "Internal Error: Missing Required paramater New Dir' "
    unless $params{'New Dir'};


  die "Internal Error: No such dir $params{'Old Dir'} "
    unless -d $params{'Old Dir'};
  die "Internal Error: No such dir $params{'New Dir'} "
    unless -d $params{'New Dir'};

  chomp($cwd = `pwd`);
  chdir ($params{'New Dir'}) or die "Could not chdir to $params{'New Dir'}:$!";
  my $ok = 0;
  $params{'Old Dir'}  =~ s|^/*||o;
  if (-d $params{'Old Dir'} ) {
    if (defined $params{'Test File'}) {
      if (-e $params{'Old Dir'} . $params{'Test File'}) {
        $ok  = 1;
      }
    } else {
      $ok = 1;                  # well, backward compatibility
    }
  }
  chdir ($cwd) or die "Could not chdir to $params{'New Dir'}:$!";
  return $ok;
}

######################################################################
######################################################################
############
######################################################################
######################################################################
sub CanonicalizePath {
  my $path = join '/', @_;
  my @work = split '/', $path;
  my @out;
  my $is_absolute;

  if (@work && $work[0] eq "") {
    $is_absolute = 1; shift @work;
  }

  while (@work) {
    my $seg = shift @work;
    if ($seg eq "." || $seg eq "") {
    } elsif ($seg eq "..") {
      if (@out && $out[-1] ne "..") {
        pop @out;
      } else {
        # Leading "..", or "../..", etc.
        push @out, $seg;
      }
    } else {
      push @out, $seg;
    }
  }

  unshift @out, "" if $is_absolute;
  return join('/', @out);
}
######################################################################
######################################################################
############
######################################################################
######################################################################

sub spath {
  my %params = @_;

  die "Missing Required paramater 'Old'" unless $params{'Old'};
  die "Missing Required paramater 'New'" unless  $params{'New'};

  my @olddir  = split '/', CanonicalizePath $params{'Old'};
  my @newdir  = split '/', CanonicalizePath $params{'New'};
  my @outdir  = @olddir;

  my $out = '';
  my $i;
  for ($i = 0; $i <= $#olddir && $i <= $#newdir; $i++) {
    $out++ if ($olddir[$i] ne $newdir[$i]);
    shift @outdir unless $out;
    unshift @outdir, ".." if $out;
  }
  if ($#newdir > $#olddir) {
    for ($i=$#olddir; $i < $#newdir; $i++) {
      unshift @outdir, "..";
    }
  }
  return join ('/', @outdir);
}
######################################################################
######################################################################
############
######################################################################
######################################################################


# This routine actually moves the kernel image
# From: $realimageloc/$kimage-$version (/boot/vmlinuz-2.6.12)
# To:   $image_dest/$kimage-$version   (/vmlinuz-2.6.12)
# Note that the image is moved to a versioned destination, but ordinary
# symlinks we create otherwise are not normally versioned
sub really_move_image {
  my $src_dir  = $_[0];
  my $target   = $_[1];
  my $dest_dir = $_[2];

  if (-e "$target") {
    # we should be in dir $dest_dir == $image_dest /, normally
    rename("$target", "$target.$$") ||
      die "failed to move " . $dest_dir . "$target:$!";
  }
  my $ret = system("mv -f " . $src_dir . "$target " .
                   " $target");
  if ($ret) {
    die("Failed to move " . $src_dir . "$target to "
        . $dest_dir . "$target.\n");
  }
  # Ok, now we may clobber the previous .old files
  if (-e "$target.$$") {
    rename("$target.$$", "$target.old") ||
      die "failed to move " . $dest_dir . "$target:$!";
  }
}

# Normally called after really_move_image; and only called if we asked for 
# reversed link this routine reverses the symbolic link that is notmally 
# created. Since the real kernel image has been moved over to 
# $image_dest/$kimage-$version. So, this routine links
# From:   $image_dest/$kimage-$version   (/vmlinuz-2.6.12)
# To:     $realimageloc/$kimage-$version (/boot/vmlinuz-2.6.12)
sub really_reverse_link {
  my $src_dir    = $_[0];
  my $link_name  = $_[1];
  my $dest_dir   = $_[2];

  my $Old = $dest_dir;
  if (test_relative ('Old Dir' => $Old, 'New Dir' => $src_dir,
                     'Test File' => "$link_name")) {
    $Old   =~ s|^/*||o;
  } elsif ($relative_links) {
    $Old = spath('Old' => "$Old", 'New' => "$src_dir" );
  }
  if ($use_hard_links =~ m/YES/i) {
    link($Old . "$link_name", $src_dir . "$link_name") ||
      die("Failed to symbolic-link " . $dest_dir . "$link_name to " . $src_dir
          . "$link_name .\n");
  }
  else {
    symlink($Old . "$link_name", $src_dir . "$link_name") ||
      die("Failed to link " . $dest_dir . "$link_name to " . $src_dir . 
          "$link_name .\n");
  }
}

# This routine is invoked if there is a symbolic link in place
# in $image_dest/$kimage -- so a symlink exists in the destination.
# What we are trying to determine is if we need to move the symbolic link over
# to the the .old location
sub move_p {
  my $kimage     = $_[0];       # Name of the symbolic link
  my $image_dest = $_[1];       # The directory the links goes into
  my $image_name = $_[2]; 
  my $src_dir    = $_[3]; 
  my $force_move = 0;

  if ($no_symlink || $reverse_symlink) {
    # we do not want links, yet we have a symbolic link here!
    warn "found a symbolic link in " . $image_dest . "$kimage \n" .
      "even though no_symlink is defined\n" if $no_symlink;
    warn "found a symbolic link in " . $image_dest . "$kimage \n" .
      "even though reverse_symlink is defined\n" if $reverse_symlink;
    # make sure we change this state of affairs
    $force_move = 1;
    return $force_move;
  }

  warn "DEBUG: OK. We found symlink, and we should have a symlink here.\n"
    if $DEBUG;
  my $vmlinuz_target = readlink "$kimage";
  my $real_target = '';
  my $target = CanonicalizePath("$realimageloc" . "$kimage-$version");
  $real_target = abs_path($vmlinuz_target) if defined($vmlinuz_target);

  if (!defined($vmlinuz_target) || ! -f "$real_target") {
    # what, a dangling symlink?
    warn "The link "  . $image_dest . "$kimage is a dangling link" .
      "to $real_target\n";
    $force_move = 1;
    return $force_move;
  }


  warn "DEBUG: The link $kimage points to ($vmlinuz_target)\n" if $DEBUG;
  warn "DEBUG: ($vmlinuz_target) is really ($real_target)\n" if $DEBUG;
  my $cwd;
  chomp ($cwd=`pwd`);
  if ($vmlinuz_target !~ m|^/|o) {
    $vmlinuz_target = $cwd . "/" . $vmlinuz_target;
    $vmlinuz_target =~ s|/+|/|o;
  }
  $vmlinuz_target = CanonicalizePath($vmlinuz_target);

  if ("$vmlinuz_target" ne "$target") {
    warn "DEBUG: We need to handle this.\n" if $DEBUG;
    if ($minimal_swap) {
      warn "DEBUG: Minimal swap.\n" if $DEBUG;
      if (-l "$kimage.old") {
        warn "DEBUG: There is an old link at $kimage.old\n" if $DEBUG;
        my $old_target = readlink "$kimage.old";
        my $real_old_target = '';
        $real_old_target=abs_path($old_target) if defined ($old_target);

        if ($real_old_target  && -f "$real_old_target") {
          if ($old_target !~ m|^/|o) {
            $old_target = $cwd . "/" . $old_target;
            $old_target =~ s|/+|/|o;
          }
          $old_target = CanonicalizePath($old_target);
          if ("$old_target"  ne "$target") {
            $force_move = 1;
            warn "DEBUG: Old link ($old_target) does not point to us ($target)\n"
              if $DEBUG;
          } 
          else {            # The .old points to the current
            warn "$kimage.old --> $target -- doing nothing";
            $force_move = 0;
          }
        } 
        else { 
          warn "DEBUG: Well, the old link does not exist -- so we move\n"
            if $DEBUG;
          $force_move = 1;
        }
      } 
      else {
        warn "DEBUG: No .old link -- OK to move\n"
          if $DEBUG;
        $force_move = 1;
      }
    } 
    else {
      warn "DEBUG: ok, minimal swap is no-- so we move.\n"
        if $DEBUG;
      $force_move = 1;
    }
  }
  else {                  # already have proper link
    warn "$kimage($vmlinuz_target) points to $target ($real_target) -- doing nothing";
    $force_move = 0;
  }
  return $force_move;
}


# This routine moves the symbolic link around (/vmlinuz -> /vmlinuz.old)
# It pays attention to whether we should the fact whether we should be using
# hard links or not.
sub really_move_link {
  my $kimage     = $_[0];       # Name of the symbolic link
  my $image_dest = $_[1];       # The directory the links goes into
  my $image_name = $_[2]; 
  my $src_dir    = $_[3]; 

  # don't clobber $kimage.old quite yet
  rename("$kimage", "$kimage.$$") ||
    die "failed to move " . $image_dest . "$kimage:$!";
  my $Old = $src_dir;
  my $cwd;

  chomp($cwd=`pwd`);
  if (test_relative ('Old Dir' => $Old, 'New Dir' => $cwd,
                     'Test File' => "$image_name")) {
    $Old   =~ s|^/*||o;
  }
  elsif ($relative_links) {
    $Old = spath('Old' => "$Old", 'New' => $cwd);
  }
  if ($use_hard_links =~ m/YES/i) {
    if (! link($Old . "$image_name", "$kimage")) {
      rename("$kimage.$$", "$kimage");
      die("Failed to link " . $realimageloc .
          "$image_name to "  . $image_dest . "$kimage .\n");
    }
  } 
  else {
    if (! symlink($Old . "$image_name", "$kimage")) {
      rename("$kimage.$$", "$kimage");
      die("Failed to symbolic-link " . $realimageloc .
          "$image_name to " . $image_dest . "$kimage .\n");
    }
  }

  # Ok, now we may clobber the previous .old file
  if (-l "$kimage.old" || ! -e "$kimage.old" ) {
    rename("$kimage.$$", "$kimage.old");
  }
  else {
    warn "$kimage.old is not a symlink, not clobbering\n";
    unlink "$kimage.$$";
  }
}

# This routine handles a request to do symlinks, but there is no
# symlink file already there.  Either we are supposed to use copy, or we are
# installing on a pristine system, or the user does not want symbolic links at
# all.  We use a configuration file to tell the last two cases apart, creating
# a config file if needed.
sub handle_missing_link {
  my $kimage     = $_[0];       # Name of the symbolic link
  my $image_dest = $_[1];       # The directory the links goes into
  my $image_name = $_[2]; 
  my $src_dir    = $_[3]; 

  if ($no_symlink) {
    my $ret = system("cp -a --backup=t " . $realimageloc .
                     "$image_name "   . " $kimage");
    if ($ret) {
      die("Failed to copy " . $realimageloc . "$image_name to "
          . $image_dest . "$kimage .\n");
    }
  } 
  elsif ($reverse_symlink) {
    my $ret = system("mv -f " . $realimageloc . "$image_name "
                     . "$kimage");
    if ($ret) {
      die("Failed to move " . $realimageloc . "$image_name to "
          . $image_dest . "$kimage .\n");
    }
  } 
  else {
    if (! $have_conffile) {
      my $answer='';
      $do_symlink = "Yes";
      print STDERR "I notice that you do not have $kimage symbolic\n";
      print STDERR "link. I can create one for you, and it shall be\n";
      print STDERR "updated by newer kernel image packages. This is\n";
      print STDERR "useful if you use a boot loader like lilo.\n";
      print STDERR "Do you want me to create a link from " .
        $realimageloc . "$image_name to $kimage?[Yn] ";
      $answer=<STDIN>;
      $answer =~ s/^\s+//;
      $answer =~ s/\s+$//;
      $do_symlink = "No" if $answer =~ /n/i;
        
      if (open(CONF, ">$CONF_LOC")) {
        print CONF "# Kernel Image management overrides\n";
        print CONF "# See kernel-img.conf(5) for details\n";
        if ($loader =~ /palo/i) {
          print CONF "link_in_boot = Yes\n";
          print CONF "do_symlinks = Yes\n";
          print CONF "relative_links = Yes\n";
          print CONF "do_bootfloppy = No\n";
          print CONF "do_bootloader = No\n";
        } else {
          print CONF "do_symlinks = $do_symlink\n";
        }
        close CONF;
      }
      $have_conffile = "Yes";
    }
  }

  if (! $no_symlink && $do_symlink =~ /Yes/i) {
    if ($reverse_symlink) {
      my $Old = $image_dest;
      if (test_relative ('Old Dir' => $Old,
                         'New Dir' => $realimageloc,
                         'Test File' => "$kimage")) {
        $Old   =~ s|^/*||o;
      } elsif ($relative_links) {
        $Old = spath('Old' => "$Old", 'New' => $realimageloc);
      }
      symlink($Old . "$kimage", $realimageloc . "$image_name")
        || die("Failed to symbolic-link " . $realimageloc
               . "$image_name to " . $image_dest . "$kimage .\n");
    }
    else {
      my $Old = $realimageloc;
      if (test_relative ('Old Dir' => $Old,
                         'New Dir' => $image_dest,
                         'Test File' => "$image_name")) {
        $Old   =~ s|^/*||o;
      } elsif ($relative_links) {
        $Old = spath('Old' => "$Old", 'New' => $image_dest);
      }
      symlink($Old . "$image_name", "$kimage") ||
        die("Failed to symbolic-link " . $realimageloc
            . "$image_name to "  . $image_dest . "$kimage .\n");
    }
  }
}

# This routine handles the rest of the cases, where the user has requested 
# non-traditional handling, like using cp, or reverse symlinks, or hard links.
sub handle_non_symlinks {
  my $kimage     = $_[0];       # Name of the symbolic link
  my $image_dest = $_[1];       # The directory the links goes into
  my $image_name = $_[2]; 
  my $src_dir    = $_[3]; 

  # Save the current image. We do this in all four cases
  rename("$kimage", "$kimage.$$") || 
    die "failed to move " . $image_dest . "$kimage:$!";

  ##,#### 
  # case One
  #`####
  if ($no_symlink) {
    # Maybe /$image_dest is on a dos system?
    my $ret = system("cp -a --backup=t " . $realimageloc
                     . "$image_name " . "$kimage");
    if ($ret) {
      if (-e "$kimage.$$") {
        rename("$kimage.$$", "$kimage");
      }
      die("Failed to copy " . $realimageloc . "$image_name to "
          . $image_dest . "$kimage .\n");
    }
  }
  ##,#### 
  # case Two
  #`####
  elsif ($reverse_symlink) {  # Maybe /$image_dest is on a dos system?
    my $ret = system("mv -f " . $realimageloc . "$image_name "
                     . $image_dest . "$kimage");
    if ($ret) {
      if (-e "$kimage.$$") {
        rename("$kimage.$$", "$kimage");
      }
      die("Failed to move " . $realimageloc . "$image_name to "
          . $image_dest . "$kimage .\n");
    }
    my $Old = $image_dest;
    if (test_relative ('Old Dir' => $Old, 'New Dir' => $realimageloc,
                       'Test File' => "$kimage")) {
      $Old   =~ s|^/*||o;
    } elsif ($relative_links) {
      $Old = spath('Old' => "$Old", 'New' => $realimageloc);
    }
    if ($use_hard_links =~ m/YES/i) {
      if (! link($Old . "$kimage", $realimageloc . "$image_name")) {
        warn "Could not link " . $image_dest .
          "$kimage to $image_name :$!";
      }
    }
    else {
      if (! symlink($Old . "$kimage", $realimageloc . "$image_name")) {
        warn "Could not symlink " . $image_dest .
          "$kimage to $image_name :$!";
      }
    }
  }
  ##,####
  # case Three
  #`####
  elsif ($use_hard_links =~ m/YES/i ) {
    # Ok then. this ought to be a hard link, and hence fair game
    # don't clobber $kimage.old quite yet
    my $Old = $realimageloc;
    my $cwd;
    chomp($cwd=`pwd`);
    if (test_relative ('Old Dir' => $Old, 'New Dir' => $cwd,
                       'Test File' => "$image_name")) {
      $Old   =~ s|^/*||o;
    } elsif ($relative_links) {
      $Old = spath('Old' => "$Old", 'New' => $cwd);
    }
    if (! link($Old . "$image_name", "$kimage")) {
      rename("$kimage.$$", "$kimage");
      die("Failed to link " . $realimageloc . "$image_name to "
          . $image_dest . "$kimage .\n");
    }
  }
  ##,####
  # case Four
  #`####
  else {
    # We just use cp
    my $ret = system("cp -a --backup=t " . $realimageloc
                     . "$image_name " . "$kimage");
    if ($ret) {
      if (-e "$kimage.$$") { rename("$kimage.$$", "$kimage");  }
      die("Failed to copy " . $realimageloc . "$image_name to "
          . $image_dest . "$kimage .\n");
    }
  }
  # Ok, now we may clobber the previous .old file
  rename("$kimage.$$", "$kimage.old") if -e "$kimage.$$";
}

# This routine is responsible for setting up the symbolic links
# So, the actual kernel image lives in
# $realimageloc/$image_name (/boot/vmlinuz-2.6.12).
# This routine creates symbolic links in $image_dest/$kimage (/vmlinuz)
sub image_magic {
  my $kimage     = $_[0];       # Name of the symbolic link
  my $image_dest = $_[1];       # The directory the links goes into
  my $image_name = $kimage-$version;
  my $src_dir    = $realimageloc;

  # Well, in any case, if the destination (the symlink we are trying
  # to create) is a directory, we should do nothing, except throw a
  # diagnostic.
  if (-d "$kimage" ) {
    die ("Hmm. $kimage is a directory, which I did not expect.  I am\n" .
         "trying to create a symbolic link with that name linked to \n" .
         "$image_dest . Since a directory exists here, my assumptions \n" .
         "are way off, and I am aborting.\n" );
    exit (3);
  }

  if ($move_image) {   # Maybe $image_dest is in on dos, or something?
    #                   source dir,    link name,        dest dir
    really_move_image(  $realimageloc, $image_name, $image_dest);
    really_reverse_link($realimageloc, $image_name, $image_dest)
      if $reverse_symlink;
    return;
  }

  if (-l "$kimage") {           # There is a symbolic link
    warn "DEBUG: There is a symlink for $kimage\n" if $DEBUG;
    my $force_move = move_p($kimage, $image_dest, $image_name, $src_dir);

    if ($force_move) {
      really_move_link($kimage, $image_dest, $image_name, $src_dir);
    }
  }
  elsif (! -e "$kimage") {
    # Hmm. Pristine system? How can that be? Installing from scratch?
    # Or maybe the user does not want a symbolic link here.
    # Possibly they do not want a link here. (we should be in /
    # here[$image_dest, really]
    handle_missing_link($kimage, $image_dest, $image_name, $src_dir);
  }
  elsif (-e "$kimage" ) {
    # OK, $kimage exists -- but is not a link
    handle_non_symlinks($kimage, $image_dest, $image_name, $src_dir);
  }
}

######################################################################
######################################################################
######################################################################
######################################################################

if ( -f "$modules_base/$version/modules.dep" ) {
  my $running = '';
  chop($running=`uname -r`);
  if ($running eq $version) {
    print STDERR <<"EOFERR";

 You are attempting to install a kernel version that is the same as
 the version you are currently running (version $running). The modules
 list is quite likely to have been changed, and the modules dependency
 file $modules_base/$version/modules.dep needs to be re-built. It can
 not be built correctly right now, since the module list for the
 running kernel are likely to be different from the kernel installed.
 I am creating a new modules.dep file, but that may not be
 correct. It shall be regenerated correctly at next reboot.

 I repeat: you have to reboot in order for the modules file to be
 created correctly. Until you reboot, it may be impossible to load
 some modules. Reboot as soon as this install is finished (Do not
 reboot right now, since you may not be able to boot back up until
 installation is over, but boot immediately after). I can not stress
 that too much. You need to reboot soon.

EOFERR
    ;
    if ($silent_modules !~ m/YES/i) {
      my $answer='';
      print "Please Hit return to continue.  ";
      $answer=<STDIN>;
    }
  }
}

# We may not have any modules installed
if ( -d "$modules_base/$version" ) {
  my $ret = system("depmod -a -F $realimageloc/System.map-$version $version");
  my $exit_value  = $? >> 8;
  my $signal_num  = $? & 127;
  my $dumped_core = $? & 128;
  if ($ret) {
    if ( -f "$modules_base/$version/modules.dep") {
      unlink "$modules_base/$version/modules.dep" unless $initrd;
    }
    print "There was a problem running depmod.  This may be benign, \n";
    print "(You may have versioned symbol names, for instance).\n";
    print "Or this could be an error.\n";
    print "\tdepmod exited with return value $exit_value\n";
    print "\tdepmod got a signal $signal_num \n" if $signal_num ;
    print "\tdepmod dumped core \n" if $dumped_core ;
    if ($initrd) {
      print "Since this image uses initrd, I am not deleting the file\n";
      print "$modules_base/$version/modules.dep. However, there is no\n";
      print "guarantee that the file is valid. I would strongly advice\n";
      print "you to either abort and fix the errors in depmod, or \n";
      print "regenerate the initrd image with a known good modules.dep\n";
      print "file. I repeat, an initrd kernel image with a bad modules.dep\n";
      print "shall fail to boot.\n";
    } else {
      print "In any case, since depmod is run at install time, \n";
      print "we could just defer running depmod\n";
    }

    if (! $ignore_depmod_err) {
      if (&ask( "Would you like to abort now")) {
        exit (1);
      } else {
        print STFERR "Ok, continuing as directed\n";
      }
    }
  }
}



# The initrd symlink should probably be in the same dir that the
# symlinks are in
if ($initrd) {
  my $initrd_path = $realimageloc . "initrd.img-$version";
  my $ret = system("$ramdisk " .
                   ($mkimage ? "-m '$mkimage' " : "") .
                   "-o $initrd_path.new $modules_base/$version");
  die("Failed to create initrd image.\n") if $ret;
  rename("$initrd_path.new", "$initrd_path")
    or die("Failed to rename initrd ($initrd_path)\n");

  if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m/<unknown>/og) {
    image_magic("initrd.img", $image_dest) if $initrd;
  } else {
    print STDERR "Not touching initrd symlinks since we are being reinstalled ($ARGV[1])\n";
  }

  if ($initrd && -l "initrd" ) {
    print STDERR <<"EOIMG";

I note that you have an old initrd symbolic link in place. The name of
the symbolic link is being changed to initrd.img I have two options
here.  I can: (A) delete the old symbolic link (default).  You shall
need to update the boot loader (b) Ignore it and do nothing

EOIMG
    ;
    my $answer='';
    print "Please select one of a, or b: ";
    $answer=<STDIN>;
    $answer =~ s/^\s+//;
    $answer =~ s/\s+$//;
    if ($answer =~ /^\s*a/i) {
      unlink "initrd";
    } else {
      print STDERR
        "Please note that initrd points to the wrong image now\n";
    }
  }

  if ($initrd && -l "$image_dir/initrd" && ! $link_in_boot) {
    print STDERR <<"EOIMG";
I note that you have an old $image_dir/initrd symbolic link in place.
The location of the symbolic link is now the same location as the kernel
image symbolic links, names, in $image_dest.  I have two options here.
I can:
 (A) delete the old symbolic link (default).  You shall need to update the
      boot loader
 (b) Ignore it and do nothing
EOIMG
    ;
    my $answer='';
    print "Please select one of a, or b: ";
    $answer=<STDIN>;
    if ($answer =~ /^\s*a/i) {
      unlink "$image_dir/initrd";
    } else {
      print STDERR
        "Please note that $image_dir/initrd points to the wrong image now\n";
    }
  }
} else {                        # Not making an initrd emage
  if (-l "initrd.img") {
    # Ooh, last image was an initrd image? in any case, we should move it. 
    my $target = readlink "initrd.img";
    my $real_target = '';
    $real_target = abs_path($target) if defined ($target);

    if (!defined($target) || ! -f "$real_target") {
      # Eh. dangling link. can safely be removed.
      unlink("initrd.img");
    } else {
      if (-l "initrd.img.old" || ! -e "initrd.img.old" ) {
        rename("initrd.img", "initrd.img.old");
      } else {
        warn "initrd.img.old is not a symlink, not clobbering\n";
        unlink("initrd.img");
      }
    }

  }
}

# Only change the symlinks if we are not being upgraded
if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m/<unknown>/og) {
  image_magic($kimage, $image_dest);
} else {
  print STDERR "Not updating image symbolic links since we are being updated ($ARGV[1])\n";
}

# We used to have System.* files in /
if (-e "/System.map" || -e "/System.old") {
  print STDERR <<"EOMAP";
 I notice that you have System.map symbolic links in /. These were
 installed by older kernel image packages. However, all the programs
 that look at the information in the map files (including top, ps, and
 klogd) also will look at /boot/System.map-<version>, we just need to
 ensure that that file is present, and no longer require the symbolic
 link.

 Actually, having the symbolic link in / is technically detrimental
 (apart from cluttering up /); many programs, though looking in /boot,
 still allow /System.map to override. If you use $Loader to choose
 between multiple kernels, then the /System.map symbolic link only
 applies to one such kernel, for all other choices the symbols loaded
 will be wrong. Not having the symbolic links at all prevents this.

 I can delete these symbolic links for you, if you wish.
EOMAP
  ;
  if ( &ask_y("Would you like to delete the obsolete links now" ) ) {
    unlink '/System.map' if -e '/System.map';
    unlink '/System.old' if -e '/System.old';
    print STFERR "Obsolete links removed.\n";
  } else {
    print STFERR
      "Ok, not deleting the files. Please remember to remove them manually.\n";
  }
}

my $linktarget;
$linktarget = "../share/doc/kernel-image-$version";


## Run user hook script here, if any
if (-x "$postinst_hook") {
  system ("$postinst_hook", $version, $realimageloc . "$kimage-$version") &&
    warn "User hook script $postinst_hook failed";
}

if (-d "/etc/kernel/postinst.d") {
  system ("run-parts", "--verbose", "--exit-on-error", "--arg=$version",
          "--arg=$realimageloc" . "$kimage-$version",
          "/etc/kernel/postinst.d") &&
            die "Failed to process /etc/kernel/postinst.d";
}

if (-d "/etc/kernel/postinst.d/$version") {
  system ("run-parts", "--verbose", "--exit-on-error", "--arg=$version",
          "--arg=$realimageloc" . "$kimage-$version",
          "/etc/kernel/postinst.d/$version") &&
            die "Failed to process /etc/kernel/postinst.d/$version";
}


exit (0) unless $do_boot_enable; # Exit if explicitly asked to

if ($loader =~ /noloader/io) {
  print STDERR << "MSGEND";
I have determined no bootloader is required for your architecure.  This is
either because there is no boot loader for your architecture, or because I
did not change anything that would cause the boot loader to be run.  However,
I could be wrong, and, if that is the case, I would appreciate it if you would
please report a bug against the kernel-package package.

Done.
MSGEND
  ;
  exit (0);
}


exit (0) if $loader =~ /silo/i; # SILO does not have to be executed.
exit (0) if $loader =~ /yaboot/i; # yaboot does not have to be executed.
exit (0) if $loader =~ /milo/i;   # MILO does not have to be executed.
exit (0) if $loader =~ /nettrom/i; # NETTROM does not have to be executed.
exit (0) if $loader =~ /arcboot/i; # ARCBOOT does not have to be executed.
exit (0) if $loader =~ /delo/i; # DELO does not have to be executed.
if ($official_image =~ /^\s*YES\s*$/o) {
  exit (0) if $loader =~ /quik/i; # maintainer asked quik invocation to be ignored
}

exit (0) unless $loaderloc;


undef $rootdevice;
undef $rootdisk;
undef $rootpartition;
undef $bootdevice;

open(FSTAB, "</etc/fstab") || die "Could not open /etc/fstab:$!";

my $line = '';
while ( $line=<FSTAB> ) {
  my $device;
  my $filesystem;
  my $ftype;
  my $foption;
  my $islilo;

  if ( $line =~ m/^\#/ ) {
    next;
  }

  # ignore leading spaces.
  $line =~ s/^\s+//og;

  #  ($device,$filesystem)=split(/[ \t]+/, $line);
  ($device,$filesystem,$ftype,$foption)=split(/[ \t]+/, $line);

  if ($device =~ m/^(LABEL|UUID)=/) {
    # Hmm. using labels in fstab.
    $device = `mount -nfv $device 2>/dev/null`;
    chomp($device);
    $device =~ s/ on\s+.*$//g;
    next if $device =~ m|^\s*$|;
  }

  next unless $device =~ m|^/dev/|; #ignore NFS and proc systems

  next if $device =~ m|^/dev/fd|;    #ignore floppy drives
  next if $device =~ m|^/dev/pty|;   #ignore Pseudo-TTY masters
  next if $device =~ m|^/dev/tty|;   #ignore Pseudo-TTY slaves
  next if $device =~ m|^/dev/cu|;    #ignore obsolete device
  next if $device =~ m|^/dev/lp|;    #ignore printers
  next if $device =~ m|^/dev/vcs|;   #ignore Virtual console capture

  next if $filesystem =~ m|^none$|; #swap? in any case, do not run dd
  next if $ftype      =~ m|^none$|; #ignore unknown file types
  next if $foption    =~ m|noauto|; #any FS not mounted at bootup time
  next if $foption    =~ m|bind|;   #ignore bind mounts

  # Looking at linux/Documentation/devices.txt, We see that really we
  # should be looking for /dev/hd* (hard disk),  /dev/sd*. What about
  # metadisk devices? ram drives? I think I'll just leave this mess
  # well enough alone.

  if ( $filesystem =~ m!^/$! ) {
    $rootdevice = $device;
  }
  unless ($loader =~ /vmelilo/io) {
    $islilo=`dd if=$device ibs=1 skip=2 count=4 2>/dev/null`;
    if ($islilo =~ /$Loader/o) {
      $bootdevice = $device;
    }
  }
  if (defined($rootdevice) && defined($bootdevice)) {
    last;
  }
}
close(FSTAB);

if (! defined($rootdevice)) {
  my $answer;
  print "Could not find where the current root file system is mounted!\n";
  print "Please make some arrangements for your system to boot the new\n";
  print "kernel (like running LILO, loadlin, SILO, QUIK, VMELILO, or  \n";
  print "getting a boot floppy).                                      \n";
  print "Please hit return to continue.                               \n";
  $answer = <STDIN>;
  exit (0);
} else {
  $rootdisk = $rootdevice;
  $rootdisk =~ s/[0-9]+$//;
  $rootpartition = $rootdevice;
  $rootpartition =~ s/$rootdisk//;
}

print "A new kernel image has been installed, and usually that means  \n";
print "that some action has to be taken to make sure that the new     \n";
print "kernel image is used next time the machine boots. Usually,     \n";
print "this entails running a ``bootloader'' like SILO, loadlin, LILO,\n";
print "ELILO, QUIK, VMELILO, ZIPL, or booting from a floppy.   (Some  \n";
print "boot loader, like grub, for example, do not need to be run on  \n";
print "each new image install, so please ignore this if you are using \n";
print "such a boot loader).\n\n";

if ( ! -x "$loaderloc" ) {
  print "Hmm. $Loader";
  printf " (LInux LOader)"                     if $loader =~ /^lilo/i;
  printf " (Efi LInux LOader)"                 if $loader =~ /^elilo/i;
  printf " (Sparc Improved Linux lOader)"      if $loader =~ /^silo/i;
  printf " (QUIK: PowerMac Boot Loader)"       if $loader =~ /^quik/i;
  printf " (yaboot: PowerMac Boot Loader)"     if $loader =~ /^yaboot/i;
  printf " (PALO: PA-RISC Boot Loader)"        if $loader =~ /^palo/i;
  printf " (VMELILO: m68k VME Boot Loader)"    if $loader =~ /^vmelilo/i;
  printf " (ZIPL: s390 & zSeries Boot Loader)" if $loader =~ /^zipl/i;
  printf " (ARCBOOT: MIPS SGI IP22  Boot Loader)" if $loader =~ /^arcboot/i;
  printf ", which is the boot loader I    \n";
  print "have additional help for, is not installed (it is, after all,\n";
  print "just one of many options). I am assuming you have made some  \n";
  print "other arrangements for your system to boot the new kernel.   \n";
  print "Please hit return to continue.                               \n";
  my $answer = <STDIN>;
  exit (0) unless defined $rootdevice;
  exit (0) if $loader =~ /^silo/i; # No idea how to make non SILO floppies
  exit (0) if $loader =~ /^quik/i;
  exit (0) if $loader =~ /^yaboot/i;
  exit (0) if $loader =~ /^palo/i; # No such thing as PALO floppies
  exit (0) if $loader =~ /^vmelilo/i;
  exit (0) if $loader =~ /^zipl/i;
  exit (0) if $loader =~ /^arcboot/i;

  if ($do_bootfloppy) {
    print "I can make a non-LILO diskette instead, but it won't be as useful.\n";

    if (&ask_y("Would you like to create a boot floppy now")) {
      &makefloppy();
    }
  }
  exit(0);
}

@boilerplate = (
                "compact\n",
                "install=/boot/boot.b",
                "\nmap=/boot/map\n",
                "vga=normal\n",
                "delay=20\n",
                "image=" . $image_dest . "$kimage\n",
                "label = Linux\n",
                "read-only\n"
               );

@silotemplate = (
                 "partition=$rootpartition\n",
                 "root=$rootdevice\n",
                 "timeout=100\n",
                 "image=" . $image_dest . "$kimage\n",
                 "\tlabel = Linux\n",
                 "\tread-only\n",
                 "other=1\n",
                 "\tbootblock=" . $rootpartition .  "/boot/old.b\n",
                 "\tlabel = oldsys\n"
                );

@quiktemplate = (
                 "partition=$rootpartition\n",
                 "root=$rootdevice\n",
                 "timeout=100\n",
                 "image=" . $image_dest . "$kimage\n",
                 "\tlabel = Linux\n",
                 "\tread-only\n",
                 "other=1\n",
                 "\tbootblock=" . $rootpartition .  "/boot/old.b\n",
                 "\tlabel=oldsys\n"
                );

@palotemplate = (
                 "# See /usr/share/doc/palo/README.html and run 'palo --help' for\n",
                 "# more information\n\n",
                 "# $rootdevice $rootdisk $rootpartition $bootdevice\n",
                 "--init-partitioned=$rootdisk\n",
                 "--bootloader=/usr/share/palo/iplboot\n",
                 "--recoverykernel=" . $image_dest . "$kimage\n",
                 "--commandline=$rootpartition" . $image_dest . "$kimage root=$rootdevice\n",
                );

@vmelilotemplate = (
                    "default   = Linux\n",
                    "delay     = 2\n",
                    "\n",
                    "[boot]\n",
                    "label     = Linux\n",
                    "image     = " . $image_dest . "$kimage\n",
                    "read-only\n"
                   );

@zipltemplate = (
                 "[defaultboot]\n",
                 "default=debian\n",
                 "\n",
                 "[debian]\n",
                 "target=/boot\n",
                 "image=" . $image_dest . "$kimage\n",
                 "parmfile=/boot/parmfile\n"
                );

@arcboottemplate = (
                    "label=arcdefault\n",
                    "image=" . $image_dest . "$kimage\n",
                   );

if ($loader =~ /^zipl/io) {
  $install_boot_method = "VM-reader or a boot tape";
} else {
  $install_boot_method = "a boot floppy";
}


# creating some info about kernel and initrd
my $ksize=sprintf("%.0f",(stat($realimageloc .
                               "$kimage-$version"))[7]/1024)."kB";
my $initrdsize='';
if ($initrd) {
  $initrdsize=sprintf("%.0f",(stat($realimageloc .
                                   "initrd.img-$version"))[7]/1024)."kB";
}


print STDERR <<"EOMSG";
A new kernel image has been installed at $realimageloc$kimage-$version
 (Size: $ksize)

EOMSG
;

if ($initrd) {
  print STDERR <<"EOMSGA";

 Initial rootdisk image: ${realimageloc}initrd.img-$version (Size: $initrdsize)
EOMSGA
  ;
}

print STDERR <<"EOMSGB";

Symbolic links, unless otherwise specified, can be found in $image_dest

$Loader sets up your system to boot Linux directly from your hard
disk, without the need for booting from $install_boot_method.

EOMSGB
;

if ($do_bootloader) {
  print STDERR <<"EOMSGC";

WARNING
If you are keeping another operating system or another version
of Linux on a separate disk partition, you should not have $Loader
install a boot block now. Wait until you read the $Loader documentation.
That is because installing a boot block now might make the other
system un-bootable. If you only want to run this version of Linux,
go ahead and install the boot block here. If it does not work, you
can still boot this system from $install_boot_method.

EOMSGC
  ;
}

if ($do_bootfloppy) {
  if (&ask("Would you like to create a boot floppy now")) {
    &makefloppy();
  }
}

exit 0 unless $do_bootloader;


if (-T "/etc/$loader.conf") {
  # Trust and use the existing lilo.conf.
  print "You already have a $Loader configuration in /etc/$loader.conf\n";
  if ($silent_loader) {
    my $ret = &run_lilo();
    exit $ret;
  } elsif ( &ask_y("Install a boot block using the existing /etc/$loader.conf")) {
    my $ret = &run_lilo();
    exit $ret;
  } elsif ($loader =~ /^elilo/io) {
    print "I don't know how to create an elilo.conf file from scratch,\n";
    print "sorry.  elilo can do that for you, if you invoke it with the\n";
    print "correct options.  Aborting.\n";
    exit(0);
  } else {
    if (&ask("Wipe out your old $Loader configuration and make a new one")) {
      my $ret = system("savelog /etc/$loader.conf");
      if ($ret) {
        print "There was a problem saving a copy of your /etc/$loader.conf\n";
        print "Since this could have grave repercussions, I am aborting.\n";
        exit(0);
      }
    } else {
      exit (0);
    }
  }
} elsif ($loader =~ /^elilo/io) {
  print "I don't know how to create an elilo.conf file from scratch,\n";
  print "sorry.  elilo can do that for you, if you invoke it with the\n";
  print "correct options.  Aborting.\n";
  exit(0);
}

if (! &ask_y("Do you wish to set up Linux to boot from the hard disk")) {
  exit (0);
}

if ($loader =~ /^lilo/io) {
  print <<EOF;

You must do three things to make the Linux system boot from the hard
disk. Install a partition boot record, install a master boot record,
and set the partition active. You will be asked to perform each of
these tasks. You may skip any or all of them, and perform them
manually later on
EOF
  ;

}

# If we get this far, we need to make a new lilo conf, and run lilo
&make_liloconf();

{ my $q;
  if ($loader =~ /vmelilo/io) {
    $q = "Install a boot block on $bootdevice";
  } else {
    $q = "Install a partition boot block on partition $bootdevice";
  }
  if (&ask_y($q)) {
    my $ret = &run_lilo();
    exit $ret if $ret;
  }
}

if ($loader =~ /^lilo/io) {
  print "\n";
  print "A master boot record is required to run the partition boot record.\n";
  if (-f "/boot/mbr.b") {
    print "If you are already using a boot manager, and want to keep it,\n";
    print "answer \"no\" to the following question. If you don't know\n";
    print "what a boot manager is or whether you have one, answer \"yes\".\n";
    if ( &ask_y("Install a master boot record (/boot/mbr.b) on $rootdisk")) {
      my $ret = system("dd if=/boot/mbr.b of=$rootdisk bs=444 count=1");
      if ($ret) {
        print "There was a problem copying the master boot record.\n";
        print "Please run \"dd if=/boot/mbr.b of=$rootdisk bs=444 count=1\"\n";
        print "by hand. Please hit return to continue.\n";
        my $ans = <STDIN>;
      }
    }
  } else {
    print "However, you do not have /boot/mbr.b, a common location of a \n";
    print "backup copy of the mbr.  I hope that your master boot record or \n";
    print "boot manager does boot the active partition.  If not, you have\n";
    print "to acquire the package mbr and install it. Please hit return to\n";
    print "proceed.\n";
    my $ans = <STDIN>;
  }
  print "\n";
  print "The master boot record will boot the active partition.\n";
  print "If you want your system to boot another operating system,\n";
  print "such as DOS or Windows, by default, answer \"no\" to the following\n";
  print "question. You may still use your boot manager or the master\n";
  print "boot record to boot Linux. If you want the system to boot Linux.\n";
  print "by default, answer \"yes\".\n";
  if ( &ask_y("Make $rootdevice the active partition") ) {
    my $ret = system("/sbin/activate $rootdisk $rootpartition");
    if ($ret) {
      print "There was an error trying to activate $rootdevice.\n";
      print "Please run \"/sbin/activate $rootdisk $rootpartition\"\n";
      print "by hand. Please hit return to proceed.\n";
      my $ans = <STDIN>;
    }
  } else {
    print "\n";
    print "OK. If you installed the master boot record, and the partition\n";
    print "boot record, you may boot Linux by holding down the shift key\n";
    print "as the system boots, and then pressing the $rootpartition key\n";
    print "when you see the \"1234F:\" prompt.\n";
    print "";
    print "For more information, see /usr/share/doc/mbr/README, and the files\n";
    print "in the /usr/share/doc/$loader directory.\n";
  }
} else {
  if (-f "/boot/old.b") {
    print "$loader has overwritten the original boot loader and saved it under\n";
    print "/boot/old.b.  You can boot your old system (if any) using the\n";
    print "oldsys label at the $loader prompt.\n";
  }
}

sub ask {
  my $answer;
  print @_,"? [No] ";
  $answer=<STDIN>;
  return ( $answer =~ /^\s*y/i );
}

sub ask_y {
  my $answer;
  print @_,"? [Yes] ";
  $answer=<STDIN>;
  return ( $answer !~ /^\s*n/i );
}

sub makefloppy {
  my $answer;
  my $done = 0;
  my $drive = 0;
  my $imageloc = '';

  return unless $do_bootfloppy;

  if ($no_symlink || $reverse_symlink) {
    $imageloc = $image_dest . $kimage;
  } else {
    $imageloc = $realimageloc . "$kimage-$version";
  }

  if (-e $imageloc) {
    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
        $atime,$mtime,$ctime,$blksize,$blocks)
      = stat ($imageloc);
    if ($size >= 520192) {
      print STDERR "Please note that the system size is $size\n";
      print STDERR "This is greater than the size that the kernel\n";
      print STDERR "loader supports on i386 machines. What this\n";
      print STDERR "means is that you need to use lilo to boot\n";
      print STDERR "this kernel on i386 machines; the floppy is\n";
      print STDERR "not going to be sufficient by itself on an \n";
      print STDERR "i386 box. Of course, things may have changed since\n";
      print STDERR "July 2000, when this diagnostic was written. Your\n";
      print STDERR "Mileage may indeed vary. Please consider yourselves\n";
      print STDERR "warned.\n";
      print STDERR "Please hit return to continue.";
      $answer=<STDIN>;
    }
  } else {
    print STDERR "Ulp!. I couldn't find the image where I expected\n";
    print STDERR "it to be, namely, $imageloc\n";
    print STDERR "You shall have to create the floppy manually, I'm\n";
    print STDERR "afraid, using commands like\n";
    print STDERR "\tdd if=/path/to/$kimage-$version of=/dev/fd$drive\n";
    print STDERR "\trdev /dev/fd$drive $rootdevice\n";
    print STDERR "\trdev -R /dev/fd$drive 1\n";
    print STDERR "Aborting\n";
    return;
  }


  print <<EO_MSG_A;

This process needs a formatted floppy. Please note that an unformatted
floppy will cause this process to fail, and may well need a reboot to
fix, and unfortunately, the system is not bootable yet.

The first thing to determine is which floppy drive you wish to use.
For most people, the default, which is the the default floppy drive,
referred to as /dev/fd0, or A: would work.  Some people may want the
second floppy drive which is drive 1, or /dev/fd1, or B:.
(Theoretically there could be 8 floppy drives on a machine) If
in doubt, accept the default [0], which should work in most cases.

EO_MSG_A
  ;

  print "Which floppy drive [0-7] do you want to use? [0] ";
  $answer=<STDIN>;
  if ($answer =~ m/^\s*(\d+)\s*$/) {
    $drive = $1;
  }
  print "\nOk, using drive at /dev/fd$drive.\n\n";

  if (-x "/usr/bin/superformat") {
    print "If there is no formatted floppy available, I could attempt\n";
    print "to format it for you.\n";
    if (&ask("Do you wish me to format the floppy")) {
      my $ret;
      my $format_command = '/usr/bin/superformat';

      print "Insert a floppy diskette into your boot drive \n";
      print "(/dev/fd$drive) and press <Return> when ready:";
      $answer=<STDIN>;
    FMTFLOPPY: while (! $done) {
      DOFORMAT:{
          $ret = system $format_command, "/dev/fd$drive";
          last DOFORMAT if $ret;
          $done = 1;
        }
        if (! $done) {
          print <<EO_MSG_B;

There was a problem formatting the floppy diskette in /dev/fd$drive

Please make sure that you inserted the disk in the correct drive and
that the disk is not write-protected.  Also, you may have to run
setfdprm for fdformat to work.

In some rare cases, it may mean a problem with the Floppy or the drive
it self (try formatting the floppy with
      % $format_command  /dev/fd$drive
manually to make sure if the problem persists).  In case the problem
persists, it maybe because you have an older fdformat which has a
problem auto- detecting the floppy drive.  Upgrading to the latest
fdutils may help, or maybe you need to run
      % setfdprm /dev/fd$drive 1440/1440
(or something like that) or you may try some thing like
      % $format_command  /dev/fd0H1440
 or even
      % $format_command  /dev/fd0u1440
manually which _may_ work. Or else, try a new floppy.

EO_MSG_B
          ;


          if (! &ask_y("Would you like to try again")) {
            print "\n";
            print "If there are no pre-formatted floppies available, \n";
            print "you should stop right here. \n";
            if (! &ask_y("Do you have a blank pre-formatted floppy")) {
              print "Ok, aborting.\n";
              print "\n";
              return 1;
            }
            print "\n";
            last FMTFLOPPY;
          }
        }
      }
    }
  } else {
    print "If there are no pre-formatted floppies available, you\n";
    print "should stop right here. \n";
    if (! &ask_y("Do you have a blank pre-formatted floppy")) {
      print "Ok, aborting.\n";
      return 1;
    }
  }
  if (!$done) {
    print "\n";
    print "Insert a (formatted) floppy diskette into your boot drive\n";
    print "(/dev/fd$drive) and press <Return> when ready:";
    $answer=<STDIN>;
  }
  $done=0;
  while (! $done) {
  MKBOOT:{
      my $ret;

      if ($loader =~ /^lilo/io) {
        if (-e "$imageloc") {
          $ret = system '/bin/dd', "if=$imageloc", "of=/dev/fd$drive";
          last MKBOOT if $ret;
          $ret = system '/usr/sbin/rdev', "/dev/fd$drive", "$rootdevice";
          last MKBOOT if $ret;
          $ret = system '/usr/sbin/rdev', '-R', "/dev/fd$drive", '1';
        } else {
          print STDERR "Ulp!. I couldn't find the image where I expected\n";
          print STDERR "it to be, namely, $imageloc\n";
          print STDERR "You shall have to create the floppy manually, I'm\n";
          print STDERR "afraid, using commands like\n";
          print STDERR "\tdd if=/path/to/$kimage-$version of=/dev/fd$drive\n";
          print STDERR "\trdev /dev/fd$drive $rootdevice\n";
          print STDERR "\trdev -R /dev/fd$drive 1\n";
          print STDERR "Aborting\n";
          return;
        }
      } else {
        $ret = &silo_floppy( $drive );
      }
      last MKBOOT if $ret;
      $done = 1;
      print "\n";
    }
    if (! $done) {
      print "\nThere was a problem creating the boot diskette in \n";
      print "/dev/fd$drive\n.";
      print "Please make sure that you inserted the diskette into the\n";
      print "correct drive and that the diskette is not write-protected.\n";
      print "In some rare cases, it may mean a problem with the\n";
      print "Floppy or the drive it self.\n";
      if (! &ask_y("Would you like to try again")) {
        $done = 1;
      } else {
        # don't display the next message if no more tries
        print "\n";
        print "Insert a (formatted) floppy diskette into your boot drive\n";
        print "/dev/fd$drive and press <Return> when ready:";
        $answer=<STDIN>;
      }
    }
  }
}

sub silo_floppy {
  my $drive = shift;
  my $mountpoint = "/var/lib/kernel.mntpoint.$$";
  my $ret = system '/sbin/mke2fs', "/dev/fd$drive";
  return $ret if $ret;
  $ret = mkdir $mountpoint, 0755;
  return $ret if $ret;
  $ret = system '/bin/mount', '-t', 'ext2', "/dev/fd$drive", $mountpoint;
  do { rmdir $mountpoint; return $ret } if $ret;
  do {
    mkdir $mountpoint . "/boot", 0755;
    last unless system '/bin/cp', '/boot/first.b', $mountpoint . '/boot';
    last unless system '/bin/cp', '/boot/second.b', $mountpoint . '/boot';
    if ($no_symlink || $reverse_symlink) {
      $ret = system '/bin/cp', $image_dest . $kimage, $mountpoint . '/linux';
    } else {
      $ret = system '/bin/cp', "$realimageloc" . "$kimage-$version",
        $mountpoint . '/linux';
    }
    last if $ret;
    mkdir( $mountpoint . "/etc", 0755 ) || last;
    open SILO, ">$mountpoint/etc/silo.conf" || last;
    print SILO
      "partition=1\n",
        "root=/dev/fd$drive\n",
          "read-write\n",
            "timeout=100\n",    # 10s
              "image = /linux\n",
                "\tlabel = Linux\n",
                  "\tappend=root=$rootdevice\n";
    close SILO;
    $ret = system '/sbin/silo', '-r', $mountpoint;
  };
  system '/bin/umount', $mountpoint;
  rmdir $mountpoint;
  return $ret;
}


sub make_liloconf {
  # Create a lilo.conf if one doesn't exist.
  print STDERR "I'll try and create a bootloader configuration filefor \n";
  print STDERR "$loader. However, please note that this is merely a best\n";
  print STDERR "effort attempt, the file /etc/$loader.conf should really\n";
  print STDERR "be checked by a human.\n";

  if (!defined($bootdevice)) {
    if ($loader =~ /vmelilo/io) {
      print "\nPutting the boot record on to $rootdisk which is\n";
      print "the device where the root file system lives.\n\n";
      $bootdevice = $rootdisk;
    } else {
      print "\nHmm... I can't determine which partition to put the \n";
      print "partition boot record on. I'm defaulting to the $rootdevice\n";
      print "which is where the root file system lives.\n";
      $bootdevice = $rootdevice;
    }
  }

  open(CONF, ">/etc/$loader.conf");
  if ($loader =~ /^lilo/io) {
    print CONF "boot=".$bootdevice, "\n", "root=".$rootdevice, "\n",
      @boilerplate;
    if ($initrd) {
      print CONF "initrd=" . $image_dest . "initrd.img\n";
    }
  } elsif ($loader =~ /^vmelilo/io) {
    print CONF "boot      = $bootdevice\n",
      "root      = $rootdevice\n",
        @vmelilotemplate;
  } elsif ($loader =~ /^quik/io) {
    print CONF @quiktemplate;
  } elsif ($loader =~ /^palo/io) {
    print CONF @palotemplate;
  } elsif ($loader =~ /^zipl/io) {
    print CONF @zipltemplate;
  } else {
    print CONF @silotemplate;
  }
  close(CONF);
  chmod("/etc/$loader.conf", 0644);
  chown("/etc/$loader.conf", 0, 0);
}

sub run_lilo (){
  my $ret;
  if ($loader =~ /^lilo/io or $loader =~ /vmelilo/io) {
    print "Testing $loader.conf ... \n";
    unlink $temp_file_name;     # security
    $ret = system("$loaderloc -t >$temp_file_name 2>&1");
    if ($ret) {
      my $ans;
      print "An error occurred while running $loader in test mode, a log is\n";
      print "available in $temp_file_name. Please edit /etc/$loader.conf\n";
      print "manually and re-run $loader, or make other arrangements to boot \n";
      print "your machine. \n\t Please hit return to continue";
      $ans = <STDIN>;
      return $ret;
    }
    unlink "$temp_file_name";
    print "Testing successful.\n";
    print "Installing the ";
    print "partition " if $loader =~ /^lilo/io;
    print "boot sector... \n";
  }

  if ($loader =~ /^elilo/io) {
    $ret = system("$loaderloc 2>&1 | tee $temp_file_name");
  } else {
    $ret = system("$loaderloc >$temp_file_name 2>&1");
  }

  if ($ret) {
    my $ans;
    print "There was an error with running $loader, a log file is \n";
    print "available in file $temp_file_name.  Please edit /etc/$loader.conf\n";
    print "manually and re-run $loader, or make other arrangements to boot \n";
    print "your machine. \n\t Please hit return to continue";
    $ans = <STDIN>;
    return $ret;
  }
  unlink $temp_file_name;
  print "Installation successful.\n";
  return 0;
}

exit 0;

__END__


Reply to: