#!/usr/bin/perl # # /usr/sbin/liloconfig -- configure lilo automatically using debconf # # Author: Bruce Perens # Bernd Eckenfels # Vincent Renardias # Peter Maydell # Russell Coker # Andrés Roldán # William Pitcock # # Maintainer: William Pitcock # Updated on 2008/07/26 -- William Pitcock # - Use large-memory by default, hoping that BIOSes now days aren't # so broken. # # Updated on 2008/06/16 -- William Pitcock # - Warn about images larger than 6.5MiB because some chipsets # cannot load them in real mode. # # Updated on 2006/08/27 -- Artur R. Czechowski # - Communication with user is handled via debconf # # Updated on 2004/07/31 -- Andrés Roldán # - Added get_bitmap() to allow one choose the bitmap to use. # # Updated on 2003/12/20 -- Andrés Roldán # - Modified get_images() to insert initrd= field when necessary. # See Bug#224368. # # Updated on 2003/10/24 -- Andrés Roldán # - Now liloconfig will smartly get the installed kernel images # and put them in the configuration file. # # Updated on 2003/10/05 -- Andrés Roldán # - Updated install= comments . See Bug#183471. # - Not using depecrated install=/boot/*b options. # # Updated on 2003/08/07 -- Andrés Roldán # - bitmap= field will search bitmaps on /boot # # Updated on 2003/04/23 -- Andrés Roldán # - added menu entry for sid and sarge from debian-bootscreen. # # Updated on 1999/01/24 -- Vincent Renardias # - never return 0 on error. # - updated the template to produce a more helpfull (commentwise) # resulting lilo.conf # # Updated on 1999/11/24 -- Peter Maydell # - added error checking of various system calls # - added $DEBUG switch and pulled lilo.conf and fstab filenames # out into config variables. # - turned on Perl's -w switch and use strict subs/refs # - now does examination of current situation up front, separated # from the logic of what we do in various situations. # - added check for special marker in /etc/fstab that indicates that we # are configuring the base filesystem and shouldn't actually do anything. # # Updated on 2000-01-23 -- Peter Maydell # - fixed a (harmless) warning produced if /etc/fstab had a blank line in it # - fixed a bug where partition number was not being pulled out of the # /dev/hda4 string correctly. # - added a paranoia check that the disk/device we get from fstab actually # exist in the filesystem. # - fixed flow-of-control problem where we simply weren't ever installing # MBR and making partition active. # - added & to some function calls, for consistency. # - changed all references to /usr/doc/lilo/ to /usr/share/doc/lilo/. # - added warning that the lilo.conf we produce does not suffice for # complicated situations. # - expanded some of the other prompts and explanatory text presented # to the user. # - added a 'ruler' to separate out questions # - questions no longer accept anything except RET as meaning 'go with # default answer'. [Previously, if the default answer was 'yes', # anything not beginning with Y or y would be interpreted as 'no'. # This is IMHO too lenient considering the consequences of getting # it wrong...] # - updated Maintainer, Author and Wishlist... # # Updated on 2000-01-25 -- Peter Maydell # - fixed important bug causing lilo not to install on RAID arrays. # (Bugs #56153,#56183,#56196) # - minor improvement to a regexp (no actual functional change) (Bug#56127) # - expanded cryptic 'iff' comment (Bug#56127) # # Updates on 2001-05-04 -- Russell Coker # - more work on devfs root support # Wishlist: # This script is from Bruce's debian.postinst and need to be more # intelligent. It should be possible to install lilo in the MBR, too. # Support for systems which dual boot (esp. dual Linux/Windows) would # also be nice, but could be complicated to get right. ###use strict 'subs'; ###use strict 'refs'; #### use strict 'vars' falls over on all the global variables :-> use Debconf::Client::ConfModule qw(:all); version('2.0'); $|=1; fset("liloconfig/banner","seen","false"); fset("liloconfig/use_current_lilo","seen","false"); fset("liloconfig/wipe_old_liloconf","seen","false"); fset("liloconfig/instruction","seen","false"); fset("liloconfig/install_from_root_device","seen","false"); fset("liloconfig/use_lba32","seen","false"); fset("liloconfig/install_mbr","seen","false"); fset("liloconfig/make_active_partition","seen","false"); fset("liloconfig/select_bitmap","seen","false"); # Set this to 1 to disable all commands that do things to the # hard disk (ie actually running lilo). Note that we still write # to $LILOCONF, so you should also tweak that to get a 'safe' test # environment. #$DEBUG=1; # Various files we access $LILOCONF='/etc/lilo.conf'; $FSTAB='/etc/fstab'; subst("liloconfig/liloconf_exists","liloconf",$LILOCONF); subst("liloconfig/lilo_warning","liloconf",$LILOCONF); subst("liloconfig/lilo_error","liloconf",$LILOCONF); subst("liloconfig/odd_fstab","liloconf",$LILOCONF); subst("liloconfig/instruction","liloconf",$LILOCONF); subst("liloconfig/fstab_broken","fstab",$FSTAB); subst("liloconfig/odd_fstab","fstab",$FSTAB); # Print a banner now, to give the user something to look at while # we ferret around in the fstab... settitle("liloconfig/maintitle"); input("low","liloconfig/banner"); # First we analyse the setup and set variables appropriately $fstab_broken = 1; # is there a valid /etc/fstab? Assume not and prove otherwise. $liloconf_exists = 0; # is there a preexisting lilo.conf with a non-commented out line? $liloconf_incompatible = 0; # does lilo.conf use options not valid for this version of lilo? $configuring_base = 0; # are we configuring the 'base' filesystem (special case) $odd_fstab = 0; # set if we don't understand the device in the fstab # We also set $device, $disk, $partition (assuming fstab_broken == 0) if (-f $FSTAB) { # Parse fstab for the root partition... open(FSTAB, "<$FSTAB") or die "liloconfig: couldn't open $FSTAB: $!\n"; while () { # Check for a magic string which indicates that we are configuring # the base filesystem and not a real machine... $configuring_base = 1 if /^# UNCONFIGURED FSTAB FOR BASE SYSTEM/; next if /^#/; # ignore comment lines s/^[ \t]+//; # remove space or tab at begin of the line ($device,$filesystem) = split(/[ \t]+/); next unless defined $filesystem; # ignore empty lines too # Stop if we found the root device... if ($filesystem eq '/') { $fstab_broken = 0; last; } } close(FSTAB) or die "liloconfig: couldn't close $FSTAB: $!\n"; } if (! $fstab_broken) { # Valid device/filesystem pair, parse them $disk = `/usr/sbin/lilo_find_mbr $device`; chomp($disk); $partition = $device; my $devfs = 0; # Paranoia check: there should be valid /dev/ nodes for these. # We could check for block-special-device-ness, but perhaps # some people have symlink forests in /dev/ ? # This check will fail on things like RAID arrays, where the # devices don't have names like /dev/hda4. In this case we can't # do simple autoconfiguration, but we still want to be able # to allow the user to install their own handrolled lilo.conf. $odd_fstab = 1 unless ($partition =~ /\d+$/ && -e $disk && -e $device); } # Check for an existing lilo.conf with some non-comment lines in it... system ("grep -qsv '^#' $LILOCONF"); # Exit status is 0 iff lilo.conf exists and contains at least one non-comment line. if ($? == 0) { $liloconf_exists = 1; $liloconf_incompatible = &compatibility_check (); } ########################################################## # Boilerplate arrays used to produce an initial lilo.conf ########################################################## @header = ( "# Generated by liloconfig\n", "\n", ); @bootheader = ( "# Specifies the boot device\n", ); @rootheader = ( "\n", "# Specifies the device that should be mounted as root.\n", "# If the special name CURRENT is used, the root device is set to the\n", "# device on which the root file system is currently mounted. If the root\n", "# has been changed with -r , the respective device is used. If the\n", "# variable ROOT is omitted, the root device setting contained in the\n", "# kernel image is used. It can be changed with the rdev program.\n" ); @boilerplate1 = ( "\n", "# Enables map compaction:\n", "# Tries to merge read requests for adjacent sectors into a single\n", "# read request. This drastically reduces load time and keeps the map\n", "# smaller. Using COMPACT is especially recommended when booting from a\n", "# floppy disk.\n", "# compact\n", "\n", "# Install the specified file as the new boot sector.\n", "# LILO supports built in boot sectory, you only need\n", "# to specify the type, choose one from 'text', 'menu' or 'bitmap'.\n", "# new: install=bmp old: install=/boot/boot-bmp.b\n", "# new: install=text old: install=/boot/boot-text.b\n", "# new: install=menu old: install=/boot/boot-menu.b or boot.b\n", "# default: 'menu' is default, unless you have a bitmap= line\n", "# Note: install=bmp must be used to see the bitmap menu.\n", "# install=menu\n", "install=bmp\n", "\n", "# Specifies the number of _tenths_ of a second LILO should\n", "# wait before booting the first image. LILO\n", "# doesn't wait if DELAY is omitted or if DELAY is set to zero.\n", "# delay=20\n", "\n", "# Prompt to use certaing image. If prompt is specified without timeout,\n", "# boot will not take place unless you hit RETURN\n", "prompt\n", "timeout=50\n", "\n", "# Enable large memory mode.\n", "large-memory\n", "\n", "# Specifies the location of the map file. If MAP is\n", "# omitted, a file /boot/map is used.\n", "map=/boot/map\n", "\n", "# Specifies the VGA text mode that should be selected when\n", "# booting. The following values are recognized (case is ignored):\n", "# NORMAL select normal 80x25 text mode.\n", "# EXTENDED select 80x50 text mode. The word EXTENDED can be\n", "# abbreviated to EXT.\n", "# ASK stop and ask for user input (at boot time).\n", "# use the corresponding text mode. A list of available modes\n", "# can be obtained by booting with vga=ask and pressing [Enter].\n", "vga=normal\n", "\n", "# Defines non-standard parameters for the specified disk.\n", "#disk=/dev/sda\n", "#\tbios=0x80\n", "\n", "# If you are using removable USB drivers (with mass-storage)\n", "# you will need to tell LILO to not use these devices even\n", "# if defined in /etc/fstab and referenced in /proc/partitions.\n", "# Adjust these lines to your devices:\n", "#\n", "# disk=/dev/sda inaccessible\n", "# disk=/dev/sdb inaccessible\n", "\n" ); @boilerplate2 = ( "# If you have another OS on this machine (say DOS),\n", "# you can boot if by uncommenting the following lines\n", "# (Of course, change /dev/hda2 to wherever your DOS partition is.)\n", "# other=/dev/hda2\n", "# label=\"MS Windows\"\n", "\n" ); #################### # Utility functions #################### sub get_bitmap { input("high","liloconfig/select_bitmap"); go(); ($ret,$val) = get("liloconfig/select_bitmap"); # each line with: [ filename,bmp-color,bmp-table,bmp-timer ] @bitmaps = ( [ "/boot/tuxlogo.bmp","6,9,0;15,9,0","59,5;1,23,","66,28;6,8,0" ], [ "/boot/inside.bmp","14,11,;15,9,0","21,284p;2,7,175p,4","73,29;12,8,0" ], [ "/boot/debian.bmp","10,0,;7,0,","16,12;1,12,16","34,28;13,0," ], [ "/boot/debian-de.bmp","10,0,;7,0,","16,12;1,12,16","34,28;13,0," ], [ "/boot/debianlilo.bmp","1,,0;9,,0","106p,144p;2,9,144p","514p,144p;6,8,0" ], [ "/boot/coffee.bmp","12,,11;15,,8","385p,100p;1,10","38,2;13,1" ], [ "/boot/onlyblue.bmp","7,,0;15,,0","3,4;4,26,19,1","37,2;7,4,0" ] ); $counter = 0; for $ref (@bitmaps) { last if ($val eq @$ref[0]); $counter++; } $ans = $counter; push (@bitmapconf, "\n# Bitmap configuration for $bitmaps[$ans][0]\n"); push (@bitmapconf, "bitmap=$bitmaps[$ans][0]\n"); push (@bitmapconf, "bmp-colors=$bitmaps[$ans][1]\n"); push (@bitmapconf, "bmp-table=$bitmaps[$ans][2]\n"); push (@bitmapconf, "bmp-timer=$bitmaps[$ans][3]\n"); return @bitmapconf; } sub get_images { my @images = (); $count = 0; print STDERR "Searching for installed kernels and updating image entries ...\n"; push (@images, "# These images were automagically added. You may need to edit something.\n\n"); # Ignore that /vmlinuz link since it can surely be poiting to # some /boot/vmlinuz* file if (-e "/vmlinuz" && ! -l "/vmlinuz") { push (@images, "image=/vmlinuz\n"); push (@images, "\tlabel=\"Linux\"\n"); if (-e "/initrd.img") { push (@images, "\tinitrd=/initrd.img\n"); } push (@images, "\tread-only\n"); push (@images, "\n"); } # Ignore that /boot/vmlinuz link as well since it can surely be # poiting to some /boot/vmlinuz* file if (-e "/boot/vmlinuz" && ! -l "/boot/vmlinuz") { push (@images, "image=/boot/vmlinuz\n"); push (@images, "\tlabel=\"Linux 1\"\n"); if (-e "/boot/initrd.img") { push (@images, "\tinitrd=/boot/initrd.img\n"); } push (@images, "\tread-only\n"); push (@images, "\n"); } foreach $image (`/bin/ls /boot/vmlinuz*`) { chomp $image; my $version = ""; my $complement = ""; if ($image =~ /vmlinuz-(\d+\.\d+\.\d+)-(.+)/) { $version = $1; $complement = $2; $label = "Lin " . $version . "img" . $count; } elsif ($image =~ /vmlinuz-(\d+\.\d+\.\d+)$/) { $version = $1; $label = "Lin " . $version . "img" . $count; } else { $label = "Lin " . "img" . $count; } push (@images, "image=$image\n"); push (@images, "\tlabel=\"$label\"\n"); if (-e "/boot/initrd.img-$version-$complement") { push (@images, "\tinitrd=/boot/initrd.img-$version-$complement\n"); } elsif (-e "/boot/initrd.img-$version") { push (@images, "\tinitrd=/boot/initrd.img-$version\n"); } push (@images, "\tread-only\n"); push (@images, "\n"); $count++; } if (-e "/boot/memtest86.bin") { push (@images, "image=/boot/memtest86.bin\n"); push (@images, "\tlabel=\"Memory Test\"\n"); push (@images, "\tread-only\n"); push (@images, "\n"); } if (-e "/boot/memtest86+.bin") { push (@images, "image=/boot/memtest86+.bin\n"); push (@images, "\tlabel=\"Memory Test+\"\n"); push (@images, "\tread-only\n"); push (@images, "\n"); } return @images; } sub asky { do { print STDERR @_,"? [Yes] "; $answer=; } while ($answer ne "\n" && !($answer =~ /^[YyNn].*/)); &ruler (); return ( !($answer =~ /^[nN].*/) ); } sub askn { do { print STDERR @_,"? [No] "; $answer=; } while ($answer ne "\n" && !($answer =~ /^[YyNn].*/)); &ruler (); return ( $answer =~ /^[yY].*/ ); } sub compatibility_check { # Check a lilo.conf for options which are not compatible # with the current version of lilo, and return 1 if any # incompatible usages are found. # This currently just checks for use of the any_* loaders. system ("egrep '^[^#]*any_' $LILOCONF"); return 1 if ($? == 0); return 0; } sub safe_system($) { # Works like system(), but just echoes the command that would # be run if $DEBUG is 1. if ($DEBUG) { print STDERR "[Would have run: ", join(' ', @_), "]\n"; $? = 0; } else { system($_[0].">&2"); } } ##################################### # Actual work is done below here... ##################################### # Debian's 'base' filesystem is a special case -- it's prebuilt # by installing and configuring packages into a subdirectory, # which is then made into a tarball, which is then used to # make the initial filesystem for a fresh Debian install. # Thus we can't actually run LILO now, because we know nothing # of the disk layout. That will be done as part of the install # process. if ($configuring_base) { input("high","liloconfig/configuring_base"); go(); exit(0); } if ($liloconf_exists) { # Trust and use the existing lilo.conf. # FIX: If the current lilo.conf installs a master boot record, ask # to edit it to a partition boot record and install the master boot # record to chain to that. input("high","liloconfig/liloconf_exists"); go(); if ($liloconf_incompatible) { input("high","liloconfig/liloconf_incompatible"); go(); exit(1); } set("liloconfig/use_current_lilo","true"); input("high","liloconfig/use_current_lilo"); go(); ($ret,$val)=get("liloconfig/use_current_lilo"); if ($val eq "true") { input("high","liloconfig/lilo_warning"); go(); stop(); &safe_system("/sbin/lilo -v"); if ( $? == 0 ) { exit(0); } input("high","liloconfig/lilo_error"); go(); exit(1); } else { set("liloconfig/wipe_old_liloconf","false"); input("high","liloconfig/wipe_old_liloconf"); go(); ($ret,$val)=get("liloconfig/wipe_old_liloconf"); if($val eq "true") { rename($LILOCONF, "$LILOCONF.OLD") or die "liloconfig: couldn't save old $LILOCONF as $LILOCONF.OLD: $!\n"; } else { input("high","liloconfig/no_changes"); go(); exit(0); } } } # ASSERT: that we get here only if there is no lilo.conf or the user # asked us to wipe out the old one... # We make checks for broken fstabs and odd devices only if we are # going to try to write a lilo.conf for the user. if ($fstab_broken) { input("high","liloconfig/fstab_broken"); go(); exit(1); } if ($odd_fstab) { subst("liloconfig/odd_fstab","device",$device); input("high","liloconfig/odd_fstab"); go(); exit(1); } input("high","liloconfig/instruction"); go(); # Flag so we can print STDERR a warning if we fell out the bottom of the config # without having run lilo at all. $lilorun = 0; $madeactive = 0; subst("liloconfig/install_from_root_device","device",$device); set("liloconfig/install_from_root_device","false"); input("high","liloconfig/install_from_root_device"); go(); ($ret,$val)=get("liloconfig/install_from_root_device"); if($val eq "true") { umask(077); open(CONF, ">$LILOCONF") or die "Couldn't open $LILOCONF for writing: $!\n"; if (!chown(0, 0, "$LILOCONF")) { die "Couldn't make $LILOCONF owned by root.root: $!\n" unless $DEBUG; # Following message is only shown if $DEBUG is set. So, I do not care # about templating it. Let it goes into STDERR. YMMV. print STDERR "Oops, couldn't make $LILOCONF owned by root.root. Since you\n"; print STDERR "have set the DEBUG flag, I'm going to assume this is because\n"; print STDERR "you're running liloconfig as a normal user, and continue anyway.\n"; } print CONF @header; input("high","liloconfig/install_from_root_device"); go(); ($ret,$val)=get("liloconfig/install_from_root_device"); if($val eq "true") { print CONF "# This allows booting from any partition on disks with more than 1024\n"; print CONF "# cylinders.\n"; print CONF "lba32\n"; print CONF "\n"; } @middle_boilerplate = &get_images; @bmp_boilerplate = &get_bitmap; print CONF @bootheader, "boot=".$device, "\n", @rootheader, "root=".$device, "\n", @bmp_boilerplate, @boilerplate1, @middle_boilerplate, @boilerplate2; close(CONF) or die "Couldn't close $LILOCONF: $!\n"; &safe_system("/sbin/lilo"); if ($? != 0) { input("high","liloconfig/lilo_error"); go(); exit(1); } $lilorun = 1; } subst("liloconfig/install_mbr","disk",$disk); set("liloconfig/install_mbr","false"); input("high","liloconfig/install_mbr"); go(); ($ret,$val)=get("liloconfig/install_mbr"); if($val eq "true") { &safe_system("install-mbr $disk"); if ($? != 0) { input("high","liloconfig/mbr_error"); go(); exit(1); } } subst("liloconfig/make_active_partition","device",$device); input("high","liloconfig/make_active_partition"); go(); ($ret,$val)=get("liloconfig/install_mbr"); if($val eq "true") { my $part_num = $partition; $part_num =~ s/^.*[a-z]//; print STDERR "Activating Partition $part_num on disk $disk.\n"; &safe_system("/sbin/activate $disk $part_num"); if ($? != 0) { input("high","liloconfig/activate_error"); go(); exit(1); } $madeactive = 1; } # Trailer: summarise what we've done print STDERR "\n"; if (! $lilorun) { print STDERR "WARNING: you will have to set up LILO manually to ensure that\n"; print STDERR " your system can be booted successfully!\n"; print STDERR "You can rerun liloconfig at any time if you change your mind and\n"; print STDERR "wish to use the default configuration.\n"; } elsif ($madeactive) { # LILO was run and Linux partition made active print STDERR "LILO successfully configured; Linux will be booted by default.\n"; print STDERR "If you installed the master boot record, you can boot a different\n"; print STDERR "OS by holding down the shift key as the system boots, and then\n"; print STDERR "pressing the key corresponding to the partition containing that\n"; print STDERR "OS when you see the \"1234F:\" prompt.\n"; } else { my $part_num = $partition; $part_num =~ s/^.*[a-z]//; # LILO run, but Linux partition not made active print STDERR "OK. If you installed the master boot record, and the partition\n"; print STDERR "boot record, you may boot Linux by holding down the shift key\n"; print STDERR "as the system boots, and then pressing the $part_num key\n"; print STDERR "when you see the \"1234F:\" prompt.\n"; } print STDERR "\n"; print STDERR "For more information about LILO, see the documentation in\n"; print STDERR "/usr/share/doc/lilo/. For details about the MBR, see also\n"; print STDERR "/usr/share/doc/mbr/.\n"; exit(0);