3 # liloconfig - creating a new lilo.conf file
6 # Copyright 2011-2014 Joachim Wiedorn <joodevel at joonet.de>
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31 #---- global variables
37 # h: help, v: verbose, f: force
43 # define perldoc usage
44 pod2usage(1) if $opt_h;
47 our $liloconf = "/etc/lilo.conf";
48 our $conftmp_1 = "/tmp/lilotmp1";
49 our $conftmp_2 = "/tmp/lilotmp2";
50 our $liloconfold = $liloconf . ".old";
51 our $liloconfnew = $liloconf . ".new";
52 our $fstabconf = "/etc/fstab";
54 our $idpath = "/dev/disk/by-id";
55 our $uuidpath = "/dev/disk/by-uuid";
56 our $lblpath = "/dev/disk/by-label";
57 our $template = "/usr/share/doc/lilo/examples/lilo.example.conf.gz";
59 our $rootpart; # found root part
60 our $root_dev; # /dev/hdX9, /dev/sdX9, /dev/md/*
61 our $root_id; # UUID, LABEL, ID
62 our $boot_dev; # /dev/hdX, /dev/sdX, /dev/md
63 our $boot_id; # DISK-ID
65 #-------------------- main program --------------------
72 $liloconf = "$ARGV[0]";
73 $liloconfold = $liloconf . ".old";
74 $liloconfnew = $liloconf . ".new";
76 if (-f $liloconf and not $opt_f and not $opt_u) {
77 print $prog .": " . $liloconf .
78 " already exist! Please force overwriting with '-f' or '-u'.\n";
82 $exit = create_lilo_conf();
87 #-------------------- subroutines --------------------
89 sub create_lilo_conf {
94 # search for root device in fstab and convert it
95 $found = detect_root_device();
97 # convert root device to boot device
98 if ($found) { $found = convert_boot_device(); }
100 # finally write new lilo.conf file
102 if ($opt_u) { $exit = update_lilo_conf(); }
103 else { $exit = write_lilo_conf(); }
109 sub detect_root_device {
111 # read fstab and find root device;
112 my $found = read_fstab();
114 # identify root device: root_dev and root_id
115 if ($found) { $found = convert_root_device(); }
124 my $broken_fstab = 1;
128 # check fstab for root device
130 # Parsing fstab for the root partition
131 open(FSTAB, "<$fstabconf") or die "$prog: couldn't open $fstabconf: $!\n";
134 # Search magic string which indicates a base filesystem
135 $base_fstab = 1 if /^# UNCONFIGURED FSTAB FOR BASE SYSTEM/;
136 next if /^#/; # ignore comment lines
138 s/^[ \t]+//; # remove space or tab at begin of the line
139 ($root_part,$mountpoint) = split(/[ \t]+/);
140 next unless defined $mountpoint; # ignore empty lines too
142 # stop if we found the root device...
143 if ($mountpoint eq '/') {
148 close(FSTAB) or die "$prog: couldn't close $fstabconf: $!\n";
152 print "E: It seems you want configure the base filesystem \n" .
153 "and I'm therefore simply going to exit successfully \n" .
154 "without trying to actually configure LILO properly. \n";
158 print "E: It seems the file /etc/fstab is not properly \n" .
159 "configured: no root partition '/' found! \n";
162 # save the found root device
163 $rootpart = $root_part;
168 sub convert_root_device {
173 # global variables: $root_dev, $root_id
175 if ($rootpart =~ /\/dev\//) {
176 $root_disk = $rootpart;
179 $root_dev = $root_disk;
180 if($opt_v) { print "Convert root option $root_disk into UUID\n"; }
181 $root_id = find_id_link($root_disk,$uuidpath);
183 if (not -l "$uuidpath/$root_id") {
184 if($opt_v) { print "W: could not find UUID for $root_disk!\n"; }
185 ## than we want use root_dev in lilo.conf
189 # finally add uuid label
190 $root_id = "UUID=" . $root_id;
194 if($opt_v) { print "E: cannot check $root_disk: device does not exist!\n"; }
198 elsif ($rootpart =~ /^UUID/ or $rootpart =~ /^LABEL/) {
199 $root_link = $rootpart;
200 $root_link =~ s{\"}{}g;
201 $root_link =~ s{^LABEL=}{/dev/disk/by-label/};
202 $root_link =~ s{^UUID=}{/dev/disk/by-uuid/};
205 $root_id = $rootpart;
206 $root_disk = readlink($root_link);
207 $root_disk =~ s{\.\./\.\./}{/dev/};
209 if (-b $root_disk) { $root_dev = $root_disk; }
211 if($opt_v) { print "E: cannot check $root_link: link does not exist!\n"; }
216 print "E: cannot check $root_link: link does not exist!\n";
221 print "E: cannot use uncommon $rootpart found as root device!\n";
237 opendir(MYDH, "$path_id") or die("cannot open $path_id: $! \n");
238 @sellinks = grep(!/\-part\d\d?$/, grep(!/^\.\.?$/, readdir(MYDH)));
239 @sellinks = sort(@sellinks);
242 foreach $_idlink (@sellinks) {
244 if(not $_idlink =~ /^usb/ and length($_idlink) > 10) {
245 $_actlink = readlink("$path_id/$_idlink");
246 $_actlink =~ s{\.\./\.\./}{/dev/};
247 if($opt_v) { print "** try: $_actlink => $_idlink \n"; }
249 # stop if we find the right link...
250 if($_actlink eq $olddev) {
251 $newdevid = $_idlink;
252 if($opt_v) { print "** convert: $_actlink => $path_id/$_idlink \n\n"; }
259 if($opt_v) { print "W: $olddev not converted: link not useful\n\n"; }
265 sub convert_boot_device {
270 # global variables: $boot_dev, $boot_id
273 if ($root_dev =~ /\/dev\/md/) {
274 # search if the found partition is a raid volume
275 $boot_disk = check_raid($root_dev);
278 # find the right block device name
279 $boot_disk = $root_dev;
280 $boot_disk =~ s/\d+$//;
284 # set global variable boot_dev
285 $boot_dev = $boot_disk;
288 print "E: boot device $boot_disk does not exist! \n";
293 print "E: could not find root device $root_dev! \n";
298 if($opt_v) { print "Convert boot option $boot_disk into DISK ID\n"; }
299 $boot_id = $idpath . "/" . find_id_link($boot_disk,$idpath);
301 if(not -l "$boot_id") {
302 if($opt_v) { print "W: could not find DISK ID for $boot_disk!\n"; }
303 ## not so important, than using boot_dev in lilo.conf
318 # check if the found partition is a raid volume
319 if($part =~ /\/dev\/md/)
322 $mdname =~ s/\/dev\///;
324 $md = `grep $mdname /proc/mdstat`;
326 @devices = split(" ", $md);
327 @devices = sort(@devices[4..$#devices]);
328 $part = "/dev/" . $devices[0];
335 sub write_lilo_conf {
338 my $exit = copy_template();
341 # create lilo.conf.new
342 write_bootroot_option();
343 if ( not write_image_config() ) {
344 if ( not write_imagelinks_config() ) {
345 print "E: Cannot find any images or image symlinks!\n";
351 if (-f $liloconf and not -f $liloconfold) {
352 # move old lilo.conf to lilo.conf.old
353 @status = stat($liloconf);
354 move ($liloconf, $liloconfold) or die "Cannot rename file: $!\n";
355 utime ($status[9],$status[9],$liloconfold);
356 chmod (0600,$liloconfold);
357 print "Old file moved to: $liloconfold \n";
359 if (-f $liloconfnew) {
360 move ($liloconfnew, $liloconf) or die "Cannot move file: $!\n";
361 chmod (0600,$liloconf);
362 print "New file created as: $liloconf \n";
363 print "Now you must execute '/sbin/lilo' to " .
364 "activate this new configuation!\n\n";
367 print "E: Cannot find temporary file $conftmp_1!\n";
379 # copy template config
381 system("gzip -d -c $template >$conftmp_1") if ($template =~ /\.gz$/);
382 system("cat $template >$conftmp_1") if ($template =~ /\.conf$/);
384 open(CONFTMP1, "<$conftmp_1") or die "$prog: couldn't open $conftmp_1: $!\n";
385 open(CONFTMP2, ">$conftmp_2") or die "$prog: couldn't open $conftmp_2: $!\n";
388 if (/first\ example/) {
391 unless ($endreached) {
395 close(CONFTMP1) or die "$prog: couldn't close $conftmp_1: $!\n";;
396 close(CONFTMP2) or die "$prog: couldn't close $conftmp_2: $!\n";;
399 open(CONFTMP2, ">$conftmp_2") or die "$prog: couldn't open $conftmp_2: $!\n";
400 print CONFTMP2 "# /etc/lilo.conf
402 ### LILO global section ###
410 menu-scheme = Wb:Yr:Wb:Wb
416 ### LILO per-image section ###
419 close(CONFTMP2) or die "$prog: couldn't close $conftmp_2: $!\n";;
425 sub update_lilo_conf {
432 system("cat $liloconf >$conftmp_2");
434 # create lilo.conf.new
435 update_bootroot_option();
438 if (-f $liloconf and not -f $liloconfold) {
439 # move old lilo.conf to lilo.conf.old
440 @status = stat($liloconf);
441 move ($liloconf, $liloconfold) or die "Cannot rename file: $!\n";
442 utime ($status[9],$status[9],$liloconfold);
443 chmod (0600,$liloconfold);
444 print "Old file moved to: $liloconfold \n";
446 if (-f $liloconfnew) {
447 move ($liloconfnew, $liloconf) or die "Cannot move file: $!\n";
448 chmod (0600,$liloconf);
449 print "New file created as: $liloconf \n";
450 print "Now you must execute '/sbin/lilo' to " .
451 "activate this new configuation!\n\n";
454 print "E: Cannot find temporary file $conftmp_1!\n";
461 sub write_bootroot_option {
467 open(MYFH_NEW, "> $liloconfnew") or die "Cannot open file: $!";
468 open(MYFH_TMP, "< $conftmp_2") or die "Cannot read file: $!";
471 # line read from MYFH_TMP
474 # lines beginning direct with boot option
475 if (/^boot/ and $ok == 0) {
477 $newline = "#boot = " . $boot_dev . "\n";
478 print MYFH_NEW $newline;
479 if($opt_v) { print $newline; }
480 $newline = "boot = " . $boot_id . "\n";
483 $newline = "boot = " . $boot_dev . "\n";
485 print MYFH_NEW $newline;
486 if($opt_v) { print $newline; print "\n";}
487 # convert only one time
490 # lines beginning direct with root option
493 $newline = '#root = ' . $root_dev . "\n";
494 print MYFH_NEW $newline;
495 if($opt_v) { print $newline; }
496 $newline = 'root = "' . $root_id . '"' . "\n";
499 $newline = 'root = ' . $root_dev . "\n";
501 print MYFH_NEW $newline;
502 if($opt_v) { print $newline; print "\n";}
504 # print the rest into file, but not old commented root lines
505 elsif ( not (/^\#boot\ =/ or /^\#root\ =/) ) {
506 print MYFH_NEW $oldline;
513 sub update_bootroot_option {
519 open(MYFH_NEW, "> $liloconfnew") or die "Cannot open file: $!";
520 open(MYFH_TMP, "< $conftmp_2") or die "Cannot read file: $!";
523 # read (old) line from MYFH_TMP
526 # lines beginning direct with boot option
527 if (/^boot/ and $ok == 0) {
529 $newline = "#boot = " . $boot_dev . "\n";
530 print MYFH_NEW $newline;
531 if($opt_v) { print $newline; }
532 $newline = "boot = " . $boot_id . "\n";
535 $newline = "boot = " . $boot_dev . "\n";
537 print MYFH_NEW $newline;
538 if($opt_v) { print $newline; print "\n";}
539 # convert only one time
542 # lines beginning direct with root option
545 $newline = '#root = ' . $root_dev . "\n";
546 print MYFH_NEW $newline;
547 if($opt_v) { print $newline; }
548 $newline = 'root = "' . $root_id . '"' . "\n";
551 $newline = 'root = ' . $root_dev . "\n";
553 print MYFH_NEW $newline;
554 if($opt_v) { print $newline; print "\n";}
556 # lines beginning with one tabulator or with two - eight spaces
557 elsif (/^\troot\ =/ or /^\ {2,8}root\ =/) {
559 $newline = "\t" . '#root = ' . $root_dev . "\n";
560 print MYFH_NEW $newline;
561 if($opt_v) { print $newline; }
562 $newline = "\t" . 'root = "' . $root_id . '"' . "\n";
565 $newline = "\t" . 'root = ' . $root_dev . "\n";
567 print MYFH_NEW $newline;
568 if($opt_v) { print $newline; print "\n";}
570 # print the rest into file, but not old commented root lines
571 elsif ( not (/^\#boot\ =/ or /^\#root\ =/ or /^\t\#root\ =/ or /^\ {2,8}\#root\ =/) ) {
572 print MYFH_NEW $oldline;
579 sub write_image_config {
587 # append to new lilo.conf
588 open(MYFH_NEW, ">> $liloconfnew") or die "Cannot open file: $!";
590 # search for kernel image files
591 my @vmlinuz = readpipe("/bin/ls -t -1 /boot/vmlinuz* 2>/dev/null");
593 # create some lines for each kernel image
595 foreach $image (@vmlinuz) {
596 # search for kernel initrd file
599 $initrd =~ s/vmlinuz/initrd\.img/;
601 $initrd2 =~ s/\.img//;
604 print MYFH_NEW 'image = ' . $image . "\n";
605 if($opt_v) { print 'image = ' . $image . "\n"; }
608 print MYFH_NEW "\t" . 'label = "Linux"' . "\n";
609 if($opt_v) { print "\t" . 'label = "Linux"' . "\n"; }
612 print MYFH_NEW "\t" . 'label = "Linux Old"' . "\n";
613 if($opt_v) { print "\t" . 'label = "Linux Old"' . "\n"; }
616 print MYFH_NEW "\t" . 'read-only' . "\n";
617 if($opt_v) { print "\t" . 'read-only' . "\n"; }
618 print MYFH_NEW "#\t" . 'restricted' . "\n";
619 if($opt_v) { print "#\t" . 'restricted' . "\n"; }
620 print MYFH_NEW "#\t" . 'alias = ' . "$nr2" . "\n";
621 if($opt_v) { print "#\t" . 'alias = ' . "$nr2" . "\n"; }
622 print MYFH_NEW "#\t" . 'optional' . "\n";
623 if($opt_v) { print "#\t" . 'optional' . "\n"; }
626 print MYFH_NEW "\t" . 'initrd = ' . $initrd . "\n";
627 if($opt_v) { print "\t" . 'initrd = ' . $initrd . "\n"; }
629 elsif (-e $initrd2) {
630 print MYFH_NEW "\t" . 'initrd = ' . $initrd2 . "\n";
631 if($opt_v) { print "\t" . 'initrd = ' . $initrd2 . "\n"; }
634 if($opt_v) { print "W: initrd $initrd could not be found!\n" }
638 if($opt_v) { print "\n"; }
647 print "No images '/boot/vmlinuz*' found!\n";
648 if($opt_v) { print "\n"; }
650 elsif( not $opt_v ) {
651 print "$nr images '/boot/vmlinuz*' found.\n";
653 return ($nr > 0); # if =0 this is an error
656 sub write_imagelinks_config {
663 # append to new lilo.conf
664 open(MYFH_NEW, ">> $liloconfnew") or die "Cannot open file: $!";
666 # search for kernel image files
667 my @vmlinuz = readpipe("/bin/ls -t -1 /vmlinuz /vmlinuz.old 2>/dev/null");
669 # create some lines for each kernel image
671 foreach $image (@vmlinuz) {
672 # search for kernel initrd file
675 $initrd =~ s/vmlinuz/initrd\.img/;
678 print MYFH_NEW 'image = ' . $image . "\n";
679 if($opt_v) { print 'image = ' . $image . "\n"; }
682 print MYFH_NEW "\t" . 'label = "Linux"' . "\n";
683 if($opt_v) { print "\t" . 'label = "Linux"' . "\n"; }
686 print MYFH_NEW "\t" . 'label = "Linux Old"' . "\n";
687 if($opt_v) { print "\t" . 'label = "Linux Old"' . "\n"; }
691 print MYFH_NEW "\t" . '#root = ' . $root_dev . "\n";
692 if($opt_v) { print "\t" . '#root = ' . $root_dev . "\n"; }
693 print MYFH_NEW "\t" . 'root = "' . $root_id . '"' . "\n";
694 if($opt_v) { print "\t" . 'root = "' . $root_id . '"' . "\n"; }
697 print MYFH_NEW "\t" . 'root = ' . $root_dev . "\n";
698 if($opt_v) { print "\t" . 'root = ' . $root_dev . "\n"; }
701 print MYFH_NEW "\t" . 'read-only' . "\n";
702 if($opt_v) { print "\t" . 'read-only' . "\n"; }
703 print MYFH_NEW "#\t" . 'restricted' . "\n";
704 if($opt_v) { print "#\t" . 'restricted' . "\n"; }
705 print MYFH_NEW "#\t" . 'alias = ' . "$nr2" . "\n";
706 if($opt_v) { print "#\t" . 'alias = ' . "$nr2" . "\n"; }
707 print MYFH_NEW "#\t" . 'optional' . "\n";
708 if($opt_v) { print "#\t" . 'optional' . "\n"; }
711 print MYFH_NEW "\t" . 'initrd = ' . $initrd . "\n";
712 if($opt_v) { print "\t" . 'initrd = ' . $initrd . "\n"; }
715 if($opt_v) { print "W: initrd $initrd could not be found!\n" }
719 if($opt_v) { print "\n"; }
728 print "No image symlinks '/vmlinuz*' found!\n";
729 if($opt_v) { print "\n"; }
731 elsif( not $opt_v ) {
732 print "$nr image symlinks '/vmlinuz*' found.\n";
734 return ($nr > 0); # if =0 this is an error
744 liloconfig - create new lilo.conf file (with diskid and uuid)
748 B<liloconfig> [B<-h>] [B<-v>] [B<-f>] [B<-u>] [B<lilo.conf>]
752 liloconfig is an simple program for creating a new lilo.conf file.
753 After creating the new configuration file you must execute '/sbin/lilo'.
755 liloconfig use the lilo.example.conf file as template. In the final
756 lilo.conf file you find many useful comments for custom changes.
758 Please pay attention about error messages if liloconfig cannot find
759 any images (/boot/vmlinuz*) oder image symlinks (/vmlinuz, /vmlinu.old).
760 Then you need to search for images by ourself and make some changes
761 in the '/etc/lilo.conf' file. Otherwise no bootloader can be installed
774 Print verbose messages.
778 Force overriding existing lilo.conf.
782 Force overriding/update of boot line in lilo.conf.
788 Lines in the configuration file /etc/lilo.conf:
790 ### LILO global section ###
796 root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44"
799 menu-scheme = Wb:Yr:Wb:Wb
805 ### LILO per-image section ###
808 boot = /dev/disk/by-id/ata-SAMSUNG_SV1604N_S01FJ10X999999
810 image = /boot/vmlinuz-3.5.0-trunk-686
813 #root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44"
818 initrd = /boot/initrd.img-3.5.0-trunk-686
820 image = /boot/vmlinuz-3.2.0-4-686
823 #root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44"
828 initrd = /boot/initrd.img-3.2.0-4-686
830 =head1 COPYRIGHT and LICENSE
832 Copyright (C) 2011-2014 Joachim Wiedorn
834 This script is free software; you can redistribute it and/or modify
835 it under the terms of the GNU General Public License as published by
836 the Free Software Foundation; either version 2 of the License, or
837 (at your option) any later version.
841 B<liloconfig> was written by Joachim Wiedorn.
843 This manual page was written by Joachim Wiedorn <joodevel at joonet.de>.
847 B<lilo>(8), B<update-lilo>(8), B<lilo-uuid-diskid>(8)