[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: