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

[debian-knoppix] Knoppix-Installer V0.1beta



Hallo Leute!

Auf allgemeinen Wunsch eines einzelnen Lesers habe ich mich entschlossen, mein Installer-Skript hiermit als Version 0.1beta freizugeben. Hierzu noch einige Kommentare:

Am besten kopiert Ihr das Skript auf eine Diskette, mountet diese von Knoppix und startet es dann von der Textkonsole (also als root). Das Skript gibt mit "-h" eine Kurzhilfe aus. Schaut dort ruhig mal rein.

Als erstes: DER KNOPPIX-INSTALLER IST GEFÄHRLICH! ER WIRD DEINE GANZE FESTPLATTE ZERSCHIESSEN UND ICH WERDE DAFÜR KEINE VERANTWORTUNG ÜBERNEHMEN! Die Hauptarbeit wird von "parted" erledigt. Während der Testläufe habe ich hier auf zwei Rechnern bestimmt 30 Partitionen erstellt, verkleinert, wieder gelöscht, vergrößert, etc. und es ist nichts passiert. Trotzdem empfehle ich wärmstens ein Backup von allen wichtigen Daten!!!

Die komplette Installation würde ich mit
  root@knoppix# knoppix-installer.pl install -v
machen. Es ist aber auch möglich, Teile des Systems alleine zu starten. (Siehe Kurzhilfe). Probiert bitte mit den Optionen herum. "-q" ist gedacht, wenn jemand das Skript aus einem graphischen Installer aufruft. Allerdings ist das noch nicht genug getestet, ich würde mit der GUI-GEschichte erstmal abwarten. Also: Testen!

----------------------------------------------------------------------
Das Programm macht im Prinzip folgendes:

Es werden alle Partitionen umount-et. Dies ist nötig, da die Partitionstabelle nur ohne reboot verändert werden kann, wenn keine der Partitionen benutzt wird.

Es wird eine ganz leere ext2-Partition gesucht. Gibt es keine, wird freier Platz auf der Platte gesucht, wenn dort welcher ist, wird dort eine neue Partition angelegt, wenn nicht, wird eine vorhandene Partition verkleinert, in deren Filesystem noch genug Platz ist.

Haben wir eine Partition, wird die Knoppix-CD hinüberkopiert. Danach werden kleinere Änderungen vorgenommen (z.B. /etc/fstab angelegt). Danach habe ich ein relativ intelligentes Programm, das versucht, eine vernünftige lilo.conf anzulegen. Dabei werden vorhandene Windows- und Linux-Partitionen erkannt und in das bootmenü eingebunden. Danach wird der bootblock mit lilo geschrieben. Fertig! Reboot muss der User selber machen.
----------------------------------------------------------------------

Ein Problem habe ich bisher noch nicht gelöst, da es mir erst in letzter Minute aufgefallen ist. Die neu angelegte Partition wird immer als logische Partition angelegt. Wenn der freie Platz aber nun nicht innerhalb der erweiterten Partition der Festplatte liegt (oder es gar keine erweiterte gibt), dürfte das nicht klappen. Es sollte aber auch keine bösen Folgen haben. Ihr könnt die Partition dann selber mit parted oder cfdisk anlegen und den Installer neu starten.

Eine zweite Sache, die ich noch vorhabe, ist, dass die lilo-bootoptionen für das neue Knoppix automatisch aus dem Knoppix-Bootimage geholt werden. Außerdem überlege ich, ob ich bootoptionen für andere Linux-Partitionen (die ihr ja wahrscheinlich alle habt) aus der lilo.conf, die innerhalb dieser Partition liegt, extrahiere.

Perl-kundige rufe ich auf, auch den Quellcode zu durchstöbern und Senf dazuzugeben. Weitere Anregungen (oder Patches) sind natürlich sehr willkommen.


Mit freundlichen Grüßen,
      Thomas Bayen

Thomas Bayen, tbayen@bayen.de
Bleichpfad 22, 47799 Krefeld, Tel. +49 2151 29262
use strict;
use warnings;
#use diagnostics;

# Knoppix-Harddisk-Installer
# (c) 2002 Thomas Bayen, t.bayen@bayen.de



# ---------------------------------------------------------------------
# config
# ---------------------------------------------------------------------
our $space_needed=2200;  # in MB
# ---------------------------------------------------------------------



# globale Variablen:
our $version='V0.1beta';
our %opts=();



# ---------------------------------------------------------------------
# Optionsparsing und Hilfetexte
# ---------------------------------------------------------------------

# Hilfe ausgeben

sub hilfe_ausgeben{
  print << "EOT";

usage:   $0 <command> [-h] [-q|-v] [-i|-t] [-r]

This tool looks for a place on your harddisk for knoppix and installs
it there. You should not mount any partitions of your hasrddisk before
starting it. It may be needed to automatic reboot your computer after
partitioning your harddisk. You have to start it again after reboot to
finish installation.

command: findpart                search an empty partition for knoppix
         makepart                make a new partition for knoppix by
	                         making other partitions smaller
	 copy     [<partition>]  copy knoppix CD to the partition
	 modify   <partition>    change some configurations to make
	                         knoppix (better) runnable from harddisk
	 liloconf <partition>    create a lilo.conf file for your system
	 lilo     <partition>    install bootloader lilo with the new
	                         lilo.conf file
	 install  [<partition>]  do everything from the above commands
	                         that are needed to get a running knoppix
         help                    show this usage/help

                                 <partition> has the form '/dev/hda1'

options: -h: show this usage/help
         -q: be quiet (output only errors)
         -v: be verbose
         -i: interactive mode. Ask before write to your harddisk.
         -t: test mode. Do not write anything to your harddisk
         -r: reboot automatic if needed
EOT
  exit;
}



# Optionen verarbeiten

sub optionen{
  my $command;
  my @arguments;
  foreach(@ARGV){
    if(/^-/){
      # Flags abfragen, die mit "-" beginnen
      my $flags=reverse $_;
      chop $flags;
      my $flag;
      while(length $flags){
        $flag=chop $flags;
        $opts{h}=1 if $flag !~ /[hqvitr]/;
        $opts{$flag}=1;
      }
    }else{
      if(defined $command){
        push @arguments, $_;
      }else{
        $command=$_;
      }
    }
  }
  # einige Flags schliessen sich aus:
  delete $opts{q} if $opts{v};
  delete $opts{i} if $opts{t};
  $command='help' if $opts{h};
  $command='help' if $command !~ /^(findpart|makepart|copy|modify|liloconf|lilo|install|help)$/i;

  # Ab hier Auswertung der Befehle...

  # Startmeldung
  if(not $opts{q}){
    print << "EOT";
$0 - Knoppix harddisk installation tool $version by T. Bayen
This is beta-software! PLEASE send your experiences to tbayen\@bayen.de.
Thank You!

YOU HAVE TO MAKE BACKUPS OF ALL YOUR HARDDISKS BEFORE STARTING THIS PROGRAM!
IT IS VERY DANGEROUS TO START IT. IT IS VERY LIKELY THAT ALL YOUR DATA WILL
BE DESTROYED!!! Do not say I did not warn you...

EOT
  }
  hilfe_ausgeben if (not defined $command) or ($command =~ /help/i);
  # Sicherheitsabfrage
  if(not ($opts{q} or $opts{t} or $opts{i})){
    print "Are You sure you want to risk destroying all your data? [NO/yes] ";
    my $eingabe=<STDIN>;
    print "\n";
    exit if $eingabe !~ /yes/i;
  }
  return $command,@arguments;
}



# ---------------------------------------------------------------------
# Schnittstellen zur Festplatte: Plattenanalyse und Schreibzugriffe
# ---------------------------------------------------------------------

# umount_alles - unmounten aller Partitionen

sub umount_alles{
  my $platte=shift;  # z.B. 'hda'
  # Vor Aendern der Partitionstabelle sollten keine Partitionen der
  # Festplatte benutzt werden. Ansonsten ist nach dem Aendern ein
  # reboot noetig.
  foreach(split /\n/,`swapon -s`){
    next if not m!^(/[\w/]+)\s+!;
    my $device=$1;
    print "Unmounting swap partition $device.\n" if not $opts{q};
    my $erg=execute("swapoff $device");
    print "Could not unmount swap $device" if $erg and not $opts{q};
  }
  foreach(split /\n/,`mount`){
    next if not m!^/dev/([a-z]+\d+) on (\S+) type!;
    my($device,$mountpoint)=($1,$2);
    next if not $device =~ /^$platte\d+/;
    print "Unmounting partition /dev/$device at mountpoint $mountpoint.\n" if not $opts{q};
    my $erg=execute("umount $mountpoint");
    print "Could not unmount /dev/$device" if $erg and not $opts{q};
  }
}

# Beispiel fuer die Ausgabe des "mount"-Befehls
#
# /dev/hda5 on / type ext2 (rw,errors=remount-ro,errors=remount-ro)
# proc on /proc type proc (rw)
# devpts on /dev/pts type devpts (rw,gid=5,mode=620)
# /dev/hda2 on /boot type ext2 (rw)
# /dev/hda7 on /var type ext2 (rw)
# /dev/hda8 on /usr type ext3 (rw)
# /dev/hdb2 on /mnt/archive type reiserfs (rw)
# none on /proc/bus/usb type usbdevfs (rw)
# //fileserver/public on /mnt/public type smbfs (0)
# /dev/fd0 on /floppy type ext2 (rw,noexec,nosuid,nodev)



# Abgleich der parted-Daten mit der Kernel-Partitionsliste, ggf. reboot

sub tabellenabgleich{
  # ich vergleiche die "parted print"-Ausgabe mit /proc/partitions
  # Dabei pruefe ich nur die Existenz von Partitionen, nicht deren Groesse
  # da ich immer auch eine neue Partition anlege, wenn ich eine veraendert
  # habe, duerfte das fuer den Knoppix-Installer kein Problem sein.
  my $partitionen=partitionsanalyse();
  my $erg=1;
  my %hash;
  foreach my $part (@$partitionen){
    my @werte=split / +/,$part;
    my $device=$werte[0].$werte[1];
    $hash{$device}=1;
  }
  my $kerneltab=`cat /proc/partitions`;
  foreach (split /\n/,$kerneltab){  # zeilenweise bearbeiten
    # Devicenamen extrahieren
    next if not /^\s*\d+\s+\d+\s+(\d+)\s+([a-z]+\d+)\s*$/;
    my($size,$device)=($1,$2);
    next if $size == 1;  # extended partition?
    # hat der Kernel eine Partition zu viel?
    undef $erg if not exists $hash{$device};  
    delete $hash{$device};
  }
  # Hat der Kernel Partitionen zu wenig?
  undef $erg if(keys %hash);
  return 1 if $erg;
  print "Kernel Partition table not actual.\n" if not $opts{q};
  print "YOU HAVE TO REBOOT before using any partitions!\n" if not $opts{q};
  if($opts{r}){
    print "AUTOMATIC REBOOT IN 10 SECONDS. Press Ctrl-C to abort." if not $opts{q};
    sleep 10 if not $opts{q};
    execute("reboot");
    exit;
  }
  return undef;
}



# Ermittlung der Harddisks im System (hda, hdb, usw.)

sub harddisks_ermitteln{
  my @disks=();
  foreach (split /\n/,`cat /proc/partitions`){  # zeilenweise bearbeiten
    # Devicenamen extrahieren
    next if not /^\s*\d+\s+\d+\s+\d+\s+([a-z]+)\s*$/;
    push @disks, $1;
  }
  return @disks;
}



# Analyse der Platten/Partitionen (basierend auf parted)

sub partitionsanalyse{
  my @partitionen=();
  foreach my $platte (harddisks_ermitteln){
    my @parts=();
    # externes Programm "parted" nutzen, um Partitions-Info zu holen
    my $parted_out = `parted -s /dev/$platte print`;
    $parted_out =~ m!.*/dev/[a-z]+: ([\d\.]+)-([\d\.]+)[^\d\.\n]*\n.*\n.*\n((?:.|\n)*)!m;
    my($start,$ende,$tabelle)=($1,$2,$3);
    if($tabelle){
      # Einzelne Partitionszeilen extrahieren:
      foreach my $zeile (split /\n/,$tabelle){
        # Eine extended-Partition interessiert uns nicht,
        # nur primäre und logische
        next if (split / +/,$zeile)[3] eq 'extended';
        push @parts,"$platte $zeile";
      }

      # Zeilen nach Lage der Partitionen auf der Platte sortieren
      # (Bevor einer fragt: Ja - das kann vorkommen)
      @parts=sort {(split / +/,$a)[2] <=> (split / +/,$b)[2]} @parts;

      # Freie Bereiche finden
      my $zaehler=0;
      my @freie=();
      foreach my $zeile (@parts){
        my ($a,$e)=(split / +/,$zeile)[2,3];
        my $diff=$a-$zaehler;
        if($diff > 1.0 ){
          # Kleinere Lücken als 1MB werden ignoriert
          push @freie, "$platte x $zaehler $a free";
        }
        $zaehler=$e;
      }
      # freier Bereich ganz am Ende der Platte?
      if($ende-$zaehler>1.0){
        push @freie, "$platte x $zaehler $ende free";
      }
      # und die freien Bereiche mit einsortieren:
      push @parts, @freie;
      @parts=sort {(split / +/,$a)[2] <=> (split / +/,$b)[2]} @parts;

      push @partitionen, @parts;
    }
  }
  return \@partitionen;
}

# Beispiel für das Ausgabeformat von partitionsanalyse():
# hda 1          0.031    956.997  primary   FAT         boot
# hda 2        956.997   1019.750  primary   ext2
# hda 3       1019.751   1451.184  primary   linux-swap
# hda 5       1451.215   1639.445  logical   ext2
# hda 6       1639.477   1827.707  logical
# hda 7       1827.738   2306.206  logical   ext2
# hda 8       2306.206   8597.316  free
# hda 9       8597.316  12409.584  logical   ext3
# hdb 1          0.031    956.997  primary   ext2
# hdb 2        956.997  39079.995  primary

sub analyse_print{
  my $partitionen=shift;
  return if not $opts{v};
  print "found these partitions and free areas:\n";
  foreach my $part (@$partitionen){
    printf "%s %2s %10.3f - %10.3f %-7s %-11s %s\n",(split / +/,$part);
  }
}



# Ausführen von externen Programmen, die die Harddisk verändern

sub execute{
  my $command=shift;
  # Test-Modus führt nichts wirklich aus
  if($opts{t}){
    return if $opts{q};
    print 'Command not executed: ' if $opts{v};
    print $command,"\n";
    return 0;
  }else{
    # Interaktiver Modus fragt erst nach
    if($opts{i}){
      print "May I execute '$command'? [Y/n] ";
      my $eingabe=<>;
      return 0 if $eingabe =~ /n/i;
    }
    print "executing '$command'\n" if $opts{v};
    return system $command;
  }
}



# ---------------------------------------------------------------------
# Manipulation von Partitionen
# ---------------------------------------------------------------------

# freien Bereich suchen (wird nur von neue_partition() benutzt)

sub freie_suchen{
  my $partitionen=shift;
  foreach my $part (@$partitionen){
    my @werte=(split / +/,$part);
    if($werte[4] eq 'free' && ($werte[3]-$werte[2])>$space_needed){
      print "found: $part\n" if $opts{v};
      return $part;
    }
  }
    print "no free area found.\n" if $opts{v};
  return undef;
}



# erzeugen einer neuen Partition in freiem Bereich
# Gibt die neue Partition zurück

sub neue_partition{
  print "creating partition in free area..." if $opts{v};
  my $partitionen=partitionsanalyse;
  # erstmal eine passende freie Partition suchen
  my $frei=freie_suchen($partitionen);
  return undef if not $frei;
  # Groessen-Werte fuer parted-Aufruf berechnen
  my @werte=(split / +/,$frei);
  my $start=$werte[2];
  my $ende=$start+$space_needed;
  my $platz=$werte[3]-$start;
  # Ist der Platz nur 10% groesser, benutze ich ihn mit, damit
  # keine unnützen Löcher entstehen
  $ende=$werte[3] if ($platz < $space_needed*1.10);
  umount_alles $werte[0];
  my $erg=execute("parted /dev/$werte[0] mkpartfs logical ext2 $start $ende");
  # Partitionstabelle neu einlesen und die neu erstellte Partition suchen
  $partitionen=partitionsanalyse;
  foreach my $part(@$partitionen){
    my @pwerte=(split / +/,$part);
    # kleinere Differenz kann schonmal auftreten, deshalb "0<x<1":
    my $diff=(split / +/,$part)[2]-$start;
    if($diff>=0 and $diff<1 and (not $pwerte[1] eq 'x')){
      my $device;
      $device="/dev/$pwerte[0]$pwerte[1]";
      print "created new partition: $device\n" if not $opts{q};
      return $device;
    }
  }
  print "could not create new partition in some free area.\n" if not $opts{q};
  return undef;
}



# überzähligen freien Platz auf einer vorhandenen Partition suchen
# ergibt eine Zeile der Partitionstabelle (Ein Device gibts ja noch nicht)

sub platz_suchen{
  print "looking for free space on existing partitions...\n" if $opts{v};
  my $partitionen=partitionsanalyse;
  mkdir '/tmp/mnt';
  foreach my $part (@$partitionen){
    my @werte=(split / +/,$part);
    my $device='/dev/'.$werte[0].$werte[1];
    print "checking $device..." if $opts{v};
    if(not defined $werte[5]){
      print "no known filesystem.\n" if $opts{v};
      next;
    }
    if($werte[5] !~ /ext[23]|FAT/i){
      print "no ext2, ext3 or fat filesystem.\n" if $opts{v};
      next;
    };
    if($werte[3]-$werte[2] < $space_needed){
      print "too small for knoppix system.\n" if $opts{v};
      next;
    }
    my $erg=system "mount -t auto $device /tmp/mnt 2>/dev/null";
    if ($erg ne 0){
      print "can't mount filesystem.\n" if $opts{v};
      next;
    }
    my $df=`df -k`;
    $df =~ m!(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\D+/tmp/mnt$!m;
    # Eine Partition ist geeignet, wenn so viel Platz ist, dass
    # sie noch 20% groesser werden kann und dann noch Platz für
    # ein Knoppix plus 5% ist. Ich will ja keine Partition
    # auslutschen bis aufs letzte Byte...
    if($2/1024*1.20+$space_needed*1.05 < $1/1024){
      print "enough free space.\n" if $opts{v};
      system 'umount /tmp/mnt';
      return $part;
    }else{
      print "not enough free space.\n" if $opts{v};
    }
    system 'umount /tmp/mnt';
  }
  return undef;
}



# vorhandene Partition verkleinern

sub platz_schaffen{
  my($part)=@_;  # $part ist eine Zeile aus der Partitionstabelle
  my @werte=(split / +/,$part);
  my $erg;
  print "making /dev/".$werte[0].$werte[1]." smaller.\n" if not $opts{q};
  # ext2-Dateisystem zur Sicherheit nochmal checken
  if($werte[5] eq 'ext2'){
    $erg=execute("e2fsck /dev/$werte[0]".$werte[1]);
    return undef if $erg;
  }
  # Ich addiere 5%, weil es sonst zu klein werden kann.
  umount_alles $werte[0];
  $erg=execute("parted /dev/$werte[0] resize $werte[1] $werte[2] ".
                  ($werte[3]-($space_needed*1.05)));
  return undef if $erg;
  # hier wird gecheckt, ob ein reboot nötig ist
  partitionsanalyse;
  # und das verkleinerte Filesystem nochmal checken (sicher ist sicher)
    if($werte[5] eq 'ext2'){
    $erg=execute("e2fsck /dev/$werte[0]".$werte[1]);
    return undef if $erg;
  }
  return 1;
}



# ggf. Platz machen und neue Partition erzeugen, die gross genug ist

sub partition_erzeugen{
  print "trying to create a new partition.\n" if not $opts{q};
  # Platz auf der Platte suchen und neue Partition erzeugen
  my $dev;
  $dev=neue_partition;
  if(not defined $dev){
    # Keinen freien Platz gefunden, also bestehende Part. verkleinern:
    my $part=platz_suchen;
    if(not defined $part){
      print "Could not find free space on the harddisk.\n" if not $opts{q};
      return undef;
    }
    return undef if not platz_schaffen($part);
    # Jetzt nochmal Platz suchen und neue Partition erzeugen
    $dev=neue_partition;
    if(not defined $dev){
      print "Can not use the created partition! Please contact tbayen\@bayen.de.\n" if not $opts{q};
    }
  }
  return $dev;
}



# ---------------------------------------------------------------------
# Kommandos, die in der Befehlszeile angegeben werden können
# ---------------------------------------------------------------------

# findpart - Suche einer leeren Partition, die gross genug ist für Knoppix

sub findpart{
  print "findpart - searching for an empty partition\n" if not $opts{q};
  my $partitionen=partitionsanalyse;
  mkdir '/tmp/mnt';
  foreach my $part (@$partitionen){
    my @werte=(split / +/,$part);
    my $device='/dev/'.$werte[0].$werte[1];
    print "checking $device..." if $opts{v};
    if(not defined $werte[5]){
      print "no known filesystem.\n" if $opts{v};
      next;
    }
    if($werte[5] !~ /ext2/i){
      print "no ext2 filesystem.\n" if $opts{v};
      next;
    };
    if($werte[3]-$werte[2] < $space_needed){
      print "too small for knoppix system.\n" if $opts{v};
      next;
    }
    my $erg=system "mount -t auto $device /tmp/mnt 2>/dev/null";
    if ($erg ne 0){
      print "can't mount filesystem.\n" if $opts{v};
      next;
    }
    my $ls=`ls /tmp/mnt`;
    system 'umount /tmp/mnt';
    $ls =~ s/lost\+found|\n|\s|//g;
    print "partition is ".(length $ls?'not':'')." free.\n" if $opts{v};
    return $device if not length $ls;
  }
  print "no free partition found.\n" if $opts{v};
  return undef;
}



# makepart - erzeugen einer neuen, leeren Partition
# (falls nicht schon eine existiert).
# Dazu ggf. Verkleinerung vorhandener Partitionen

sub makepart{
  print "makepart - create new empty partition for knoppix\n" if not $opts{q};
  my $device=findpart;
  if(not defined $device){
    partition_erzeugen;
    exit if not tabellenabgleich;  # Kernel-Partitionstabelle verwirrt?
    $device=findpart;
  }
  return $device;
}



# copy - kopieren der Knoppix-CD in die angegebene (oder eine freie) Partition

sub copy{
  my $device=shift;
  print "copy - copy Knoppix CD to a free harddisk partition\n" if not $opts{q};
  $device=findpart if not defined $device;
  if(not defined $device){
    print "could not find a free partition. try <makepart> first.\n" if not $opts{q};
    return undef;
  }
  mkdir '/tmp/mnt';
  my $erg=system "mount -t auto -o dev $device /tmp/mnt 2>/dev/null";
  if($erg ne 0){
      print "Can not mount $device\n" if (not $opts{q});
      return undef;
  }
  print "copying knoppix system...\n" if $opts{v};
  execute "cp -a /KNOPPIX/* /tmp/mnt";
  system "umount /tmp/mnt 2>/dev/null";
  return $device;
}



# modify - Anpassen des Knoppix-Systems an die neue Umgebung

sub modify{
  my $device=shift;
  print "modify - configuring the system for harddisk usage\n" if not $opts{q};
  if(not defined $device){
    print "no device.\n" if not $opts{q};
    return undef;
  }
  mkdir '/tmp/mnt';
  my $erg=system "mount -t auto -o dev $device /tmp/mnt 2>/dev/null";
  if($erg ne 0){
      print "Can not mount $device\n" if (not $opts{q});
      return undef;
  }
  print "modifying knoppix system...\n" if $opts{v};

  # /mnt-Eintraege erzeugen (brauche ich für lilo)
  execute 'cp -ax /mnt /tmp/mnt/';

  # die fstab braucht mind. zwei Einträge zum booten:
  open(FILE,'>/tmp/mnt/etc/fstab');
  print FILE << "EOT";
# /etc/fstab made by knoppix-installer $version (c) T.Bayen
proc		/proc		proc	defaults			0 0
none		/dev/pts	devpts	mode=0622			0 0
/dev/fd0	/mnt/floppy	auto	user,noauto,exec		0 0
/dev/cdrom	/mnt/cdrom	auto	user,noauto,exec,ro		0 0
$device 	/ 		ext2 	defaults,errors=remount-ro 	0 1
# end of knoppix-installer
# rest of this file made by knoppix autoconfig or user modifications...

EOT
  close FILE;

  # Home-Verzeichnis anlegen
  execute('mkdir -m 0755 /tmp/mnt/home/knoppix');
  execute('chown knoppix.knoppix /tmp/mnt/home/knoppix');
  execute('mkdir -m 0755 /tmp/mnt/home/root');

  # fertig, jetzt wieder unmounten
  system "umount /tmp/mnt 2>/dev/null";
  return $device;
}



# liloconf - Erzeugen einer richtig guten lilo.conf

sub liloconf{
  my $device=shift;
  print "liloconf - creating a lilo.conf file suited for your system\n" if not $opts{q};
  if(not defined $device){
    print "no device.\n" if not $opts{q};
    return undef;
  }
  mkdir '/tmp/mnt';
  my $erg=system "mount -t auto -o dev $device /tmp/mnt 2>/dev/null";
  if($erg ne 0){
      print "Can not mount $device\n" if (not $opts{q});
      return undef;
  }
  print "creating lilo.conf...\n" if $opts{v};
  my $disk=$device;
  $disk=~s/\d//g;  # HD-Device ohne Partitionsnummer
  # Sicherheitskopie der alten lilo.conf
  execute 'mv /tmp/mnt/etc/lilo.conf /tmp/mnt/etc/lilo.conf.org';
  if(not $opts{t}){
    open FILE, '>/tmp/mnt/etc/lilo.conf';
    print FILE << "EOT";
# LILO-Configuration
# build automatic by the knoppix-harddisk-installer Version $version
# written by T. Bayen (tbayen\@bayen.de)

lba32
boot=$disk
install=/boot/boot.b
map=/boot/map
timeout=100
delay=20
prompt
#lock

# standard Knoppix image
image=/vmlinuz
	root=$device
	label=Knoppix
	read-only
	append="lang=de apm=power-off hda=scsi hdb=scsi hdc=scsi hdd=scsi vga=791 quiet BOOT_IMAGE=knoppix"

# standard Knoppix image in expert mode
image=/vmlinuz
	root=$device
	label=expert
	read-only
	append="lang=de apm=power-off hda=scsi hdb=scsi hdc=scsi hdd=scsi vga=791 BOOT_IMAGE=expert"

# This entry is used if you install a new kernel via a debian package
image=/vmlinuz.old
	label=Knoppix-OLD
	root=$device
	read-only
	optional
EOT
    # Jetzt gehe ich alle Partitionen durch, um ggf.
    # dafür noch lilo-Einträge zu generieren.
    my $partitionen=partitionsanalyse;
    my ($gefunden_linux,$gefunden_dos);
    my @mounts;  # ich merke mir, was ich wieder unmounten muss
    foreach my $other_part (@$partitionen){
      my @other_werte=(split / +/,$other_part);
      my $other_device=$other_werte[0].$other_werte[1];
      # das eben erstellte Knoppix nicht mehr prüfen
      next if "/dev/$other_device" eq $device;
      next if not defined $other_werte[5];  # gar kein (bekanntes) Filesystem
      if($other_werte[5] =~ /ext[23]/){
        # Linux-System gefunden
        next if system "mount -t auto -o dev,ro /dev/$other_device /tmp/mnt/mnt/$other_device";
        # bootfaehig? Erkenne ich am /boot-Verzeichnis
        if(not -e "/tmp/mnt/mnt/$other_device/boot"){
          system "umount /tmp/mnt/mnt/$other_device";
          next;
        }
        # Den Kernel zu finden ist nicht ganz trivial, da manche
        # Distris einen Link /vmlinuz und manche /boot/vmlinuz
        # benutzen und dieser Link manchmal "/boot/vmlinuz-2.2.17"
        # und manchmal "boot/vmlinuz-2.2.17" heisst. :-(
        my $ls;
        if(-e "/tmp/mnt/mnt/$other_device/vmlinuz"){
          $ls=`ls -l /tmp/mnt/mnt/$other_device/`;
        }else{
          $ls=`ls -l /tmp/mnt/mnt/$other_device/boot/`;
        }
        $ls =~ /vmlinuz ->.*(vmlinuz.*)$/m;
        if(not defined $1){
          print "Could not find kernel on $other_device. No lilo entry generated.\n" if $opts{v};
          system "umount /tmp/mnt/mnt/$other_device";
          next;
        }
        print "/dev/$other_device: found bootable linux.\n" if $opts{v};
        my $image="/mnt/$other_device/boot/$1";
        my $label=$gefunden_linux?"Linux$other_device":'Linux';
        $gefunden_linux=1;
        print FILE << "EOT";
# Linux-Partition
# you have to mount /mnt/$other_device before starting lilo!
image=$image
	root=/dev/$other_device
	label=$label
	read-only
	optional
EOT
        # Die Partition bleibt gemountet, damit lilo den
        # Kernel finden kann
        push @mounts, $other_device;
      }elsif($other_werte[5] =~ /fat/i){
        # Windows-System gefunden
        # bootfaehig?
        next if (not defined $other_werte[6]) or ($other_werte[6] !~ /boot/);
        print "/dev/$other_device: found bootable DOS/Windows.\n" if $opts{v};
        my $label=$gefunden_dos?"Windows$other_device":'Windows';
        $gefunden_dos=1;
        print FILE << "EOT";

# DOS/Windows-Partition
other=/dev/$other_device
	label=$label
EOT
      }
    }
    # Die gemounteten Partitionen wieder freigeben
    # und als Kommentar in die Datei schreiben (fuer lilo() und den User)
    if(@mounts){
      print FILE << "EOT";

# Before starting lilo, you have to mount the following partitions
# to get all possible entries in your bootmenu:
EOT
      foreach my $m (@mounts){
        system "umount /tmp/mnt/mnt/$m";
        print FILE "# mount /mnt/$m\n";
      }
    }
    close FILE;
  }
  system "umount /tmp/mnt 2>/dev/null";
  return $device;
}



# lilo - Starten von lilo. Dabei Einbinden aller bootfähigen Partitionen

sub lilo{
  my $device=shift;
  print "lilo - installation of the bootloader\n" if not $opts{q};
  if(not defined $device){
    print "no device.\n" if not $opts{q};
    return undef;
  }
  mkdir '/tmp/mnt';
  my $erg=system "mount -t auto -o dev $device /tmp/mnt 2>/dev/null";
  if($erg ne 0){
      print "Can not mount $device\n" if (not $opts{q});
      return undef;
  }
  print "installing bootloader...\n" if $opts{v};
  my $offen=open FILE, '</tmp/mnt/etc/lilo.conf';
  if(not $offen){
    print "Can't find lilo.conf.\n" if not $opts{q};
    return undef;
  }
  # Linux-Partitionen mounten, auf denen sich Kernel befinden
  my @mounts;  # merken für umount
  my $liloconf=join '',<FILE>;
  close FILE;
  while($liloconf =~ m!^# mount /mnt/(.*)$!mg){
    my $device=$1;
    print "mounting /dev/$device.\n" if $opts{v};
    system "mount -t auto -o dev,ro /dev/$device /tmp/mnt/mnt/$device";
    push @mounts, $device;
  }
  # jetzt lilo aufrufen
  chdir '/tmp/mnt/';
  my $optionen=($opts{v}?'-v':'');   # -v für lilo
  execute "lilo $optionen -r /tmp/mnt";
  # die gemounteten Partitionen wieder freigeben
  foreach my $m (@mounts){
    system "umount /tmp/mnt/mnt/$m";
  }
  chdir '/';
  system "umount /tmp/mnt";
  return $device;
}



# install - Alle Installationsschritte hintereinander

sub install{
  my $device=shift;
  print "install - doing all necessary installation steps\n" if not $opts{q};
  return lilo liloconf modify copy ($device or makepart);
}



# ---------------------------------------------------------------------
# Hauptprogramm
# ---------------------------------------------------------------------

# Kommandozeilenoptionen einlesen
my($command,@arguments)=optionen;

# Ich sperre hier die Kernel-Meldungen, da ich sonst beim Aufruf von
# parted etliche Meldungen "invalidate: busy buffer" bekomme!?!
system 'echo 0 >/proc/sys/kernel/printk';
no strict 'refs';
my $erg=&$command(@arguments);
system 'echo 6 >/proc/sys/kernel/printk';

if(defined $erg){
  print "$erg\n";
  exit;
}else{
  exit 1;
}

Reply to: