From 9650ecddd0276a177310655d8424473cbd3a955e Mon Sep 17 00:00:00 2001 From: Joachim Wiedorn Date: Sun, 20 Mar 2011 15:41:31 +0100 Subject: [PATCH] Add new script liloconfig --- debian/changelog | 4 +- debian/manpages/liloconfig.8 | 83 ----- debian/scripts/liloconfig | 598 +++++++++++++++++++++++++++++++++++ 3 files changed, 601 insertions(+), 84 deletions(-) diff --git a/debian/changelog b/debian/changelog index 169f2be..b2b2654 100644 --- a/debian/changelog +++ b/debian/changelog @@ -26,8 +26,10 @@ lilo (1:23.1-2) unstable; urgency=low - Update of Italian translation (it.po). (Closes: #618801) - Update of Brazilian Portuguese translation. (Closes: #618738) - Update of Swedish translation (sv.po). (Closes: #618620) + * Add new script liloconfig, using template with comments, + works with UUID, LABEL and disk-id for root and boot options. - -- Joachim Wiedorn Sat, 19 Mar 2011 23:34:00 +0100 + -- Joachim Wiedorn Sat, 19 Mar 2011 23:50:00 +0100 lilo (1:23.1-1) unstable; urgency=low diff --git a/debian/manpages/liloconfig.8 b/debian/manpages/liloconfig.8 index 731aba9..e69de29 100644 --- a/debian/manpages/liloconfig.8 +++ b/debian/manpages/liloconfig.8 @@ -1,83 +0,0 @@ -'\" t -.\" This page is not actually based on the original LILO docs, -.\" but I'm using the same COPYING conditions: -.\" -.\" This manual page is: -.\" Copyright 1999 Peter Maydell -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms of parts of or the -.\" whole original or derived work are permitted provided that the -.\" original work is properly attributed to the author. The name of the -.\" author may not be used to endorse or promote products derived from -.\" this software without specific prior written permission. This work -.\" is provided "as is" and without any express or implied warranties. -.\" -.TH LILOCONFIG 8 "September 1999" -.SH NAME -liloconfig \- interactive configure script for lilo -.SH SYNOPSIS -.B liloconfig -.SH DESCRIPTION -.LP -.B liloconfig -is an interactive program which will ask you a series of questions -and write a -.B lilo.conf(5) -configuration file for you. It will also set up the Master Boot Record -(MBR) so that Linux will boot from hard disk. -It is normally run automatically whenever you upgrade the -.B lilo(8) -Debian package. - -The configuration file generated by -.B liloconfig -is intended for common installations; if your setup is complicated -or unusual you should consider writing your own customised -.B lilo.conf. -To do this you should refer to the comprehensive -.B lilo -documentation, which can be found in -/usr/share/doc/lilo/ on Debian systems. - -If you have already written your own -.B lilo.conf -then the script will ask you if you wish to keep it, in which case -it will check it for options which are incompatible with the current -version of -.B lilo -and run -.B lilo -to install the boot block. - -If you have no -.B lilo.conf -or choose to overwrite it, -.B liloconfig -will perform three operations to ensure that the Linux system will -boot from the hard disk: -install LILO in the Linux partition's boot record, install a -simple MBR, and mark the Linux partition as the active partition. -You will be prompted prior to each of these operations, so you -can skip them and perform them manually later on. - -The automatically generated -.B lilo.conf -contains helpful comments, so it might well be a good place to start -even if you wish to roll your own configuration file. - -.SH AUTHOR -Bruce Perens , -.br -Bernd Eckenfels -.br -and Vincent Renardias . - -Peter Maydell (pmaydell@chiark.greenend.org.uk) wrote this manual page. -.SH SEE ALSO -.BR lilo (8), -.BR lilo.conf (5) - -.B lilo -comes with extensive documentation; this can be found in -/usr/share/doc/lilo/ on Debian systems. diff --git a/debian/scripts/liloconfig b/debian/scripts/liloconfig index 7becf55..46a83f5 100644 --- a/debian/scripts/liloconfig +++ b/debian/scripts/liloconfig @@ -1,3 +1,601 @@ #!/usr/bin/perl -w +# liloconfig - creating a new lilo.conf file +# +# Copyright 2011 Joachim Wiedorn +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +#---- some modules +use strict; +use warnings; +use Getopt::Std; +use Pod::Usage; +use File::Copy; + + +#---- global variables +my $prog = $0; +$prog =~ s#.*/##; +my $version = "0.1"; + +#---- parameter check +# h: help, v: verbose, f: force +our $opt_h = 0; +our $opt_v = 0; +our $opt_f = 0; +getopts('hvf'); +# define perldoc usage +pod2usage(1) if $opt_h; + +#---- other variables +our $liloconf = "/etc/lilo.conf"; +our $conftmp_1 = "/tmp/lilotmp1"; +our $conftmp_2 = "/tmp/lilotmp2"; +our $liloconfold = $liloconf . ".old"; +our $liloconfnew = $liloconf . ".new"; +our $fstabconf = "/etc/fstab"; + +our $idpath = "/dev/disk/by-id"; +our $uuidpath = "/dev/disk/by-uuid"; +our $lblpath = "/dev/disk/by-label"; +our $template = "/usr/share/doc/lilo/examples/lilo.example.conf.gz"; + +our $rootpart; # found root part +our $root_dev; # /dev/hdX9, /dev/sdX9, /dev/md/* +our $root_id; # UUID, LABEL, ID +our $boot_dev; # /dev/hdX, /dev/sdX, /dev/md +our $boot_id; # DISK-ID + +#-------------------- main program -------------------- + +sub main { + + my $exit = 0; + + if (@ARGV == 1) { + $liloconf = "$ARGV[0]"; + $liloconfold = $liloconf . ".old"; + $liloconfnew = $liloconf . ".new"; + } + if (-f $liloconf and not $opt_f) { + print "$prog: $liloconf already exist! Please use '-f' for overwriting.\n"; + $exit = 1; + } + else { + $exit = create_lilo_conf() + } + return $exit; +} + +#-------------------- subroutines -------------------- + +sub create_lilo_conf { + + my $found = 0; + my $exit = 1; + + # search for root device in fstab and convert it + $found = detect_root_device(); + + # convert root device to boot device + if ($found) { $found = convert_boot_device(); } + + # finally write new lilo.conf file + if ($found) { $exit = write_lilo_conf(); } + + return $exit; +} + +sub detect_root_device { + + # read fstab and find root device; + my $found = read_fstab(); + + # identify root device: root_dev and root_id + if ($found) { $found = convert_root_device(); } + + return $found; +} + +sub read_fstab { + + my $root_part; + my $mountpoint; + my $broken_fstab = 1; + my $base_fstab = 0; + my $found = 1; + + # check fstab for root device + if (-f $fstabconf) { + # Parsing fstab for the root partition + open(FSTAB, "<$fstabconf") or die "$prog: couldn't open $fstabconf: $!\n"; + + while () { + # Search magic string which indicates a base filesystem + $base_fstab = 1 if /^# UNCONFIGURED FSTAB FOR BASE SYSTEM/; + next if /^#/; # ignore comment lines + + s/^[ \t]+//; # remove space or tab at begin of the line + ($root_part,$mountpoint) = split(/[ \t]+/); + next unless defined $mountpoint; # ignore empty lines too + + # stop if we found the root device... + if ($mountpoint eq '/') { + $broken_fstab = 0; + last; + } + } + close(FSTAB) or die "$prog: couldn't close $fstabconf: $!\n"; + } + + if ($base_fstab) { + print "E: It seems you want configure the base filesystem \n" . + "and I'm therefore simply going to exit successfully \n" . + "without trying to actually configure LILO properly. \n"; + $found = 0; + } + if ($broken_fstab) { + print "E: It seems the file /etc/fstab is not properly \n" . + "configured: no root partition '/' found! \n"; + $found = 0; + } + # save the found root device + $rootpart = $root_part; + + return $found; +} + +sub convert_root_device { + + my $found = 1; + my $root_disk = ''; + my $root_link; + # global variables: $root_dev, $root_id + + if ($rootpart =~ /\/dev\//) { + $root_disk = $rootpart; + + if (-b $root_disk) { + $root_dev = $root_disk; + if($opt_v) { print "Convert root option $root_disk into UUID\n"; } + $root_id = find_id_link($root_disk,$uuidpath); + + if (not -l "$uuidpath/$root_id") { + if($opt_v) { print "W: could not find UUID for $root_disk!\n"; } + ## than we want use root_dev in lilo.conf + #$found = 0; + } + else { + # finally add uuid label + $root_id = "UUID=" . $root_id; + } + } + else { + if($opt_v) { print "E: cannot check $root_disk: device does not exist!\n"; } + $found = 0; + } + } + elsif ($rootpart =~ /^UUID/ or $rootpart =~ /^LABEL/) { + $root_link = $rootpart; + $root_link =~ s{\"}{}g; + $root_link =~ s{^LABEL=}{/dev/disk/by-label/}; + $root_link =~ s{^UUID=}{/dev/disk/by-uuid/}; + + if (-l $root_link) { + $root_id = $rootpart; + $root_disk = readlink($root_link); + $root_disk =~ s{\.\./\.\./}{/dev/}; + + if (-b $root_disk) { $root_dev = $root_disk; } + else { + if($opt_v) { print "E: cannot check $root_link: link does not exist!\n"; } + $found = 0; + } + } + else { + print "E: cannot check $root_link: link does not exist!\n"; + $found = 0; + } + } + else { + print "E: cannot use uncommon $rootpart found as root device!\n"; + $found = 0; + } + + return $found; +} + +sub find_id_link { + + my $olddev = $_[0]; + my $path_id = $_[1]; + my @sellinks; + my $_idlink; + my $_actlink; + my $newdevid = ''; + + opendir(MYDH, "$path_id") or die("cannot open $path_id: $! \n"); + @sellinks = grep(!/\-part\d\d?$/, grep(!/^\.\.?$/, readdir(MYDH))); + @sellinks = sort(@sellinks); + closedir(MYDH); + + foreach $_idlink (@sellinks) { + chomp $_idlink; + if(not $_idlink =~ /^usb/ and length($_idlink) > 10) { + $_actlink = readlink("$path_id/$_idlink"); + $_actlink =~ s{\.\./\.\./}{/dev/}; + if($opt_v) { print "** try: $_actlink => $_idlink \n"; } + + # stop if we find the right link... + if($_actlink eq $olddev) { + $newdevid = $_idlink; + if($opt_v) { print "** convert: $_actlink => $path_id/$_idlink \n\n"; } + last; + } + } + } + + if(not $newdevid) { + if($opt_v) { print "W: $olddev not converted: link not useful\n\n"; } + } + + return ($newdevid); +} + +sub convert_boot_device { + + my $found = 1; + my $boot_disk = ''; + my $boot_link; + # global variables: $boot_dev, $boot_id + + if (-b $root_dev) { + if ($root_dev =~ /\/dev\/md/) { + # search if the found partition is a raid volume + $boot_disk = check_raid($root_dev); + } + else { + # find the right block device name + $boot_disk = $root_dev; + $boot_disk =~ s/\d+$//; + } + + if (-b $boot_disk) { + # set global variable boot_dev + $boot_dev = $boot_disk; + } + else { + print "E: boot device $boot_disk does not exist! \n"; + $found = 0; + } + } + else { + print "E: could not find root device $root_dev! \n"; + $found = 0; + } + + if ($found) { + if($opt_v) { print "Convert boot option $boot_disk into DISK ID\n"; } + $boot_id = $idpath . "/" . find_id_link($boot_disk,$idpath); + + if(not -l "$boot_id") { + if($opt_v) { print "W: could not find DISK ID for $boot_disk!\n"; } + ## not so important, than using boot_dev in lilo.conf + #$found = 0; + } + } + + return $found; +} + +sub check_raid { + + my $part = $_[0]; + my $mdname; + my $md; + my @devices; + + # check if the found partition is a raid volume + if($part =~ /\/dev\/md/) + { + $mdname = $part; + $mdname =~ s/\/dev\///; + $mdname =~ s/\///; + $md = `grep $mdname /proc/mdstat`; + + @devices = split(" ", $md); + @devices = sort(@devices[4..$#devices]); + $part = "/dev/" . $devices[0]; + $part =~ s/\[.*$//; + + } + return $part; +} + +sub write_lilo_conf { + + my @status; + my $exit = copy_template(); + + if (not $exit) { + # create lilo.conf.new + write_boot_option(); + write_image_config(); + } + + if (-f $liloconf and not -f $liloconfold) { + # move old lilo.conf to lilo.conf.old + @status = stat($liloconf); + move ($liloconf, $liloconfold) or die "Cannot rename file: $!\n"; + utime ($status[9],$status[9],$liloconfold); + chmod (0600,$liloconfold); + print "Old file moved to: $liloconfold \n"; + } + if (-f $liloconfnew) { + move ($liloconfnew, $liloconf) or die "Cannot move file: $!\n"; + chmod (0600,$liloconf); + print "New file created as: $liloconf \n"; + print "Now you must execute '/sbin/lilo' to " . + "activate this new configuation!\n\n"; + } + else { + print "E: Cannot find temporary file $conftmp_1!\n"; + $exit = 1; + } + + return $exit; +} + +sub copy_template { + + my $endreached = 0; + my $exit = 0; + + # copy template config + if (-f $template) { + system("gzip -d -c $template >$conftmp_1") if ($template =~ /\.gz$/); + system("cat $template >$conftmp_1") if ($template =~ /\.conf$/); + + open(CONFTMP1, "<$conftmp_1") or die "$prog: couldn't open $conftmp_1: $!\n"; + open(CONFTMP2, ">$conftmp_2") or die "$prog: couldn't open $conftmp_2: $!\n"; + + while () { + if (/first\ example/) { + $endreached = 1; + } + unless ($endreached) { + print CONFTMP2 $_; + } + } + close(CONFTMP1) or die "$prog: couldn't close $conftmp_1: $!\n";; + close(CONFTMP2) or die "$prog: couldn't close $conftmp_2: $!\n";; + } + else { + open(CONFTMP2, ">$conftmp_2") or die "$prog: couldn't open $conftmp_2: $!\n"; + print CONFTMP2 "# /etc/lilo.conf + +### LILO global section ### + +#large-memory +lba32 +boot = /dev/sda +map = /boot/map +install = menu +menu-scheme = Wb:Yr:Wb:Wb +prompt +timeout = 100 +vga = normal +#default = Linux + +### LILO per-image section ### + +"; + close(CONFTMP2) or die "$prog: couldn't close $conftmp_2: $!\n";; + } + + return $exit; +} + +sub write_boot_option { + + my $oldline = ''; + my $newline = ''; + my $ok = 0; + + open(MYFH_NEW, "> $liloconfnew") or die "Cannot open file: $!"; + open(MYFH_TMP, "< $conftmp_2") or die "Cannot read file: $!"; + + while () { + # line read from MYFH_TMP + $oldline = $_; + + if (/^boot/ and $ok == 0) { + if ($boot_id) { + $oldline = "#boot = $boot_dev\n"; + $newline = "boot = $boot_id\n"; + print MYFH_NEW $oldline; + if($opt_v) { print $oldline; } + } + else { + $oldline = "boot = $boot_dev\n"; + } + print MYFH_NEW $newline; + if($opt_v) { print $newline; } + if($opt_v) { print "\n"; } + + # convert only one time + $ok = 1; + } + else { + print MYFH_NEW $oldline; + } + } + close(MYFH_TMP); + close(MYFH_NEW); +} + +sub write_image_config { + + my $image; + my $initrd; + my $nr; + my $nr2; + + # search for kernel image files + my @vmlinuz = readpipe("/bin/ls -t -1 /boot/vmlinuz-2* 2>/dev/null"); + + # append to new lilo.conf + open(MYFH_NEW, ">> $liloconfnew") or die "Cannot open file: $!"; + + # create some line for each kernel image + $nr = 0; + foreach $image (@vmlinuz) { + # search for kernel initrd file + chomp $image; + $initrd = $image; + $initrd =~ s/vmlinuz/initrd\.img/; + $nr2 = $nr + 1; + + print MYFH_NEW 'image = ' . $image . "\n"; + if($opt_v) { print 'image = ' . $image . "\n"; } + if ($nr == 0) { + print MYFH_NEW "\t" . 'label = "Linux"' . "\n"; + if($opt_v) { print "\t" . 'label = "Linux"' . "\n"; } + } + elsif ($nr == 1) { + print MYFH_NEW "\t" . 'label = "Linux Old"' . "\n"; + if($opt_v) { print "\t" . 'label = "Linux Old"' . "\n"; } + } + if ($root_id) { + print MYFH_NEW "\t" . '#root = ' . $root_dev . "\n"; + if($opt_v) { print "\t" . '#root = ' . $root_dev . "\n"; } + print MYFH_NEW "\t" . 'root = "' . $root_id . '"' . "\n"; + if($opt_v) { print "\t" . 'root = "' . $root_id . '"' . "\n"; } + } + else { + print MYFH_NEW "\t" . 'root = ' . $root_dev . "\n"; + if($opt_v) { print "\t" . 'root = ' . $root_dev . "\n"; } + } + print MYFH_NEW "\t" . 'read-only' . "\n"; + if($opt_v) { print "\t" . 'read-only' . "\n"; } + print MYFH_NEW "#\t" . 'restricted' . "\n"; + if($opt_v) { print "#\t" . 'restricted' . "\n"; } + print MYFH_NEW "#\t" . 'alias = ' . "$nr2" . "\n"; + if($opt_v) { print "#\t" . 'alias = ' . "$nr2" . "\n"; } + print MYFH_NEW "#\t" . 'optional' . "\n"; + if($opt_v) { print "#\t" . 'optional' . "\n"; } + if (-f $initrd) { + print MYFH_NEW "\t" . 'initrd = ' . $initrd . "\n"; + if($opt_v) { print "\t" . 'initrd = ' . $initrd . "\n"; } + } + print MYFH_NEW "\n"; + if($opt_v) { print "\n"; } + + $nr++; + last if ($nr > 1); + } + + close(MYFH_NEW); +} + + +main(); + __END__ + + +=head1 NAME + +liloconfig - create new lilo.conf file (with diskid and uuid) + +=head1 SYNOPSIS + +liloconfig [-h] [-v] [-f] [lilo.conf] + +=head1 DESCRIPTION + +liloconfig is an simple program for creating a new lilo.conf file. +After creating the new configuration file you must execute '/sbin/lilo'. + +liloconfig use the lilo.example.conf file as template. In the final +lilo.conf file you find many useful comments for custom changes. + +=head1 EXAMPLES + +Lines in the configuration file /etc/lilo.conf: + + ### LILO global section ### + + #large-memory + lba32 + boot = /dev/sda + map = /boot/map + install = menu + menu-scheme = Wb:Yr:Wb:Wb + prompt + timeout = 100 + vga = normal + #default = Linux + + ### LILO per-image section ### + + #boot = /dev/sda + boot = /dev/disk/by-id/ata-SAMSUNG_SV1604N_S01FJ10X999999 + + image = /boot/vmlinuz-2.6.32-5book-686 + label = "Linux" + #root = /dev/sda1 + root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44" + read-only + # restricted + # alias = 1 + # optional + initrd = /boot/initrd.img-2.6.32-5book-686 + + image = /boot/vmlinuz-2.6.32-5-686 + label = "Linux Old" + #root = /dev/sda1 + root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44" + read-only + # restricted + # alias = 2 + # optional + initrd = /boot/initrd.img-2.6.32-5-686 + +=head1 OPTIONS + +=over 4 + +=item B<-h> + +Print a brief help. + +=item B<-v> + +Print verbose messages. + +=item B<-f> + +Force overriding existing lilo.conf. + +=back + +=head1 AUTHOR + +B was written by Joachim Wiedorn. + +=cut -- 2.39.2