3 # liloconfig - creating a new lilo.conf file
6 # Copyright 2011-2015 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 {
96 # read fstab and search for root device
97 $found1 = read_fstab();
101 # nothing found, exit by error
104 # identify root device: root_dev and root_id
105 { $found2 = convert_root_device(); }
107 # nothing found, but exit successfully
108 { $exit = 0; $found2 = 0;}
112 # nothing found, exit by error
115 # convert root device to boot device
116 { $found3 = convert_boot_device(); }
118 # nothing found, but exit successfully
119 { $exit = 0; $found2 = 3;}
123 # nothing found, exit by error
125 elsif ($found3 == 1) {
126 if ((-f $liloconf) and not (-w $liloconf)) {
127 print "E: Have no write permissions to $liloconf !\n";
131 # finally write new/updated lilo.conf file
132 if ($opt_u) { $exit = update_lilo_conf(); }
133 else { $exit = write_lilo_conf(); }
137 # nothing found, but exit successfully
147 my $broken_fstab = 1;
151 # check fstab for root device
153 # Parsing fstab for the root partition
154 open(FSTAB, "<$fstabconf") or die "$prog: couldn't open $fstabconf: $!\n";
157 # Search magic string which indicates a base filesystem
158 $base_fstab = 1 if /^# UNCONFIGURED FSTAB FOR BASE SYSTEM/;
159 next if /^#/; # ignore comment lines
161 s/^[ \t]+//; # remove space or tab at begin of the line
162 ($root_part,$mountpoint) = split(/[ \t]+/);
163 next unless defined $mountpoint; # ignore empty lines too
165 # stop if we found the root device...
166 if ($mountpoint eq '/') {
171 close(FSTAB) or die "$prog: couldn't close $fstabconf: $!\n";
175 print "E: It seems you want configure the base filesystem \n" .
176 "and I'm therefore simply going to exit successfully \n" .
177 "without trying to actually configure LILO properly. \n";
181 print "E: It seems the file /etc/fstab is not properly \n" .
182 "configured: no root partition '/' found! \n";
185 # save the found root device
186 $rootpart = $root_part;
191 sub convert_root_device {
196 # global variables: $root_dev, $root_id
198 if ($rootpart =~ /\/dev\//) {
199 $root_disk = $rootpart;
202 $root_dev = $root_disk;
203 if($opt_v) { print "Convert root option $root_disk into UUID\n"; }
204 $root_id = find_id_link($root_disk,$uuidpath);
206 if (not -l "$uuidpath/$root_id") {
207 if($opt_v) { print "W: could not find UUID for $root_disk!\n"; }
208 # than we will use root_dev in lilo.conf
211 # finally add uuid label
212 $root_id = "UUID=" . $root_id;
216 if($opt_v) { print "E: cannot check $root_disk: device does not exist!\n"; }
220 elsif ($rootpart =~ /^UUID/ or $rootpart =~ /^LABEL/) {
221 $root_link = $rootpart;
222 $root_link =~ s{\"}{}g;
223 $root_link =~ s{^LABEL=}{/dev/disk/by-label/};
224 $root_link =~ s{^UUID=}{/dev/disk/by-uuid/};
227 $root_id = $rootpart;
228 $root_disk = readlink($root_link);
229 $root_disk =~ s{\.\./\.\./}{/dev/};
231 if (-b $root_disk) { $root_dev = $root_disk; }
233 if($opt_v) { print "E: cannot check $root_link: link does not exist!\n"; }
238 print "E: cannot check $root_link: link does not exist!\n";
243 print "E: cannot use uncommon $rootpart found as root device!\n";
259 opendir(MYDH, "$path_id") or die("cannot open $path_id: $! \n");
260 @sellinks = grep(!/\-part\d\d?$/, grep(!/^\.\.?$/, readdir(MYDH)));
261 @sellinks = sort(@sellinks);
264 foreach $_idlink (@sellinks) {
266 if(not $_idlink =~ /^usb/ and length($_idlink) > 10) {
267 $_actlink = readlink("$path_id/$_idlink");
268 $_actlink =~ s{\.\./\.\./}{/dev/};
269 if($opt_v) { print "** try: $_actlink => $_idlink \n"; }
271 # stop if we find the right link...
272 if($_actlink eq $olddev) {
273 $newdevid = $_idlink;
274 if($opt_v) { print "** convert: $_actlink => $path_id/$_idlink \n\n"; }
281 if($opt_v) { print "W: $olddev not converted: link not useful\n\n"; }
287 sub convert_boot_device {
292 # global variables: $boot_dev, $boot_id
295 if ($root_dev =~ /\/dev\/md/) {
296 # search if the found partition is a raid volume
297 $boot_disk = check_raid($root_dev);
300 # find the right block device name
301 $boot_disk = $root_dev;
302 $boot_disk =~ s/\d+$//;
306 # set global variable boot_dev
307 $boot_dev = $boot_disk;
310 print "E: boot device $boot_disk does not exist! \n";
315 print "E: could not find root device $root_dev! \n";
320 if($opt_v) { print "Convert boot option $boot_disk into DISK ID\n"; }
321 $boot_id = $idpath . "/" . find_id_link($boot_disk,$idpath);
323 if(not -l "$boot_id") {
324 if($opt_v) { print "W: could not find DISK ID for $boot_disk!\n"; }
325 # not so important. Then using boot_dev in lilo.conf
339 # check if the found partition is a raid volume
340 if($part =~ /\/dev\/md/)
343 $mdname =~ s/\/dev\///;
345 $md = `grep $mdname /proc/mdstat`;
347 @devices = split(" ", $md);
348 @devices = sort(@devices[4..$#devices]);
349 $part = "/dev/" . $devices[0];
356 sub write_lilo_conf {
359 my $exit = copy_template();
362 # create lilo.conf.new
363 write_bootroot_option();
364 if ( not write_image_config() ) {
365 if ( not write_imagelinks_config() ) {
366 print "E: Cannot find any images or image symlinks!\n";
372 if (-f $liloconf and not -f $liloconfold) {
373 # move old lilo.conf to lilo.conf.old
374 @status = stat($liloconf);
375 move ($liloconf, $liloconfold) or die "Cannot rename file: $!\n";
376 utime ($status[9],$status[9],$liloconfold);
377 chmod (0600,$liloconfold);
378 print "Old file moved to: $liloconfold \n";
380 if (-f $liloconfnew) {
381 move ($liloconfnew, $liloconf) or die "Cannot move file: $!\n";
382 chmod (0600,$liloconf);
383 print "New file created as: $liloconf \n";
384 print "Now you must execute '/sbin/lilo' to " .
385 "activate this new configuation!\n\n";
388 print "E: Cannot find temporary file $conftmp_1!\n";
400 # copy template config
402 system("gzip -d -c $template >$conftmp_1") if ($template =~ /\.gz$/);
403 system("cat $template >$conftmp_1") if ($template =~ /\.conf$/);
405 open(CONFTMP1, "<$conftmp_1") or die "$prog: couldn't open $conftmp_1: $!\n";
406 open(CONFTMP2, ">$conftmp_2") or die "$prog: couldn't open $conftmp_2: $!\n";
409 if (/first\ example/) {
412 unless ($endreached) {
416 close(CONFTMP1) or die "$prog: couldn't close $conftmp_1: $!\n";;
417 close(CONFTMP2) or die "$prog: couldn't close $conftmp_2: $!\n";;
420 open(CONFTMP2, ">$conftmp_2") or die "$prog: couldn't open $conftmp_2: $!\n";
421 print CONFTMP2 "# /etc/lilo.conf
423 ### LILO global section ###
431 menu-scheme = Wb:Yr:Wb:Wb
437 ### LILO per-image section ###
440 close(CONFTMP2) or die "$prog: couldn't close $conftmp_2: $!\n";;
446 sub update_lilo_conf {
453 system("cat $liloconf >$conftmp_2");
455 # create lilo.conf.new
456 update_bootroot_option();
459 if (-f $liloconf and not -f $liloconfold) {
460 # move old lilo.conf to lilo.conf.old
461 @status = stat($liloconf);
462 move ($liloconf, $liloconfold) or die "Cannot rename file: $!\n";
463 utime ($status[9],$status[9],$liloconfold);
464 chmod (0600,$liloconfold);
465 print "Old file moved to: $liloconfold \n";
467 if (-f $liloconfnew) {
468 move ($liloconfnew, $liloconf) or die "Cannot move file: $!\n";
469 chmod (0600,$liloconf);
470 print "New file created as: $liloconf \n";
471 print "Now you must execute '/sbin/lilo' to " .
472 "activate this new configuation!\n\n";
475 print "E: Cannot find temporary file $conftmp_1!\n";
482 sub write_bootroot_option {
488 open(MYFH_NEW, "> $liloconfnew") or die "Cannot open file: $!";
489 open(MYFH_TMP, "< $conftmp_2") or die "Cannot read file: $!";
492 # line read from MYFH_TMP
495 # lines beginning direct with boot option
496 if (/^boot/ and $ok == 0) {
498 $newline = "#boot = " . $boot_dev . "\n";
499 print MYFH_NEW $newline;
500 if($opt_v) { print $newline; }
501 $newline = "boot = " . $boot_id . "\n";
504 $newline = "boot = " . $boot_dev . "\n";
506 print MYFH_NEW $newline;
507 if($opt_v) { print $newline; print "\n";}
508 # convert only one time
511 # lines beginning direct with root option
514 $newline = '#root = ' . $root_dev . "\n";
515 print MYFH_NEW $newline;
516 if($opt_v) { print $newline; }
517 $newline = 'root = "' . $root_id . '"' . "\n";
520 $newline = 'root = ' . $root_dev . "\n";
522 print MYFH_NEW $newline;
523 if($opt_v) { print $newline; print "\n";}
525 # print the rest into file, but not old commented root lines
526 elsif ( not (/^\#boot\ =/ or /^\#root\ =/) ) {
527 print MYFH_NEW $oldline;
535 sub update_bootroot_option {
541 open(MYFH_NEW, "> $liloconfnew") or die "Cannot open file: $!";
542 open(MYFH_TMP, "< $conftmp_2") or die "Cannot read file: $!";
545 # read (old) line from MYFH_TMP
548 # lines beginning direct with boot option
549 if (/^boot/ and $ok == 0) {
551 $newline = "#boot = " . $boot_dev . "\n";
552 print MYFH_NEW $newline;
553 if($opt_v) { print $newline; }
554 $newline = "boot = " . $boot_id . "\n";
557 $newline = "boot = " . $boot_dev . "\n";
559 print MYFH_NEW $newline;
560 if($opt_v) { print $newline; print "\n";}
561 # convert only one time
564 # lines beginning direct with root option
567 $newline = '#root = ' . $root_dev . "\n";
568 print MYFH_NEW $newline;
569 if($opt_v) { print $newline; }
570 $newline = 'root = "' . $root_id . '"' . "\n";
573 $newline = 'root = ' . $root_dev . "\n";
575 print MYFH_NEW $newline;
576 if($opt_v) { print $newline; print "\n";}
578 # lines beginning with one tabulator or with two - eight spaces
579 elsif (/^\troot\ =/ or /^\ {2,8}root\ =/) {
581 $newline = "\t" . '#root = ' . $root_dev . "\n";
582 print MYFH_NEW $newline;
583 if($opt_v) { print $newline; }
584 $newline = "\t" . 'root = "' . $root_id . '"' . "\n";
587 $newline = "\t" . 'root = ' . $root_dev . "\n";
589 print MYFH_NEW $newline;
590 if($opt_v) { print $newline; print "\n";}
592 # print the rest into file, but not old commented root lines
593 elsif ( not (/^\#boot\ =/ or /^\#root\ =/ or /^\t\#root\ =/ or /^\ {2,8}\#root\ =/) ) {
594 print MYFH_NEW $oldline;
602 sub write_image_config {
610 # append to new lilo.conf
611 open(MYFH_NEW, ">> $liloconfnew") or die "Cannot open file: $!";
613 # search for kernel image files
614 my @vmlinuz = readpipe("/bin/ls -t -1 /boot/vmlinuz* 2>/dev/null");
616 # create some lines for each kernel image
618 foreach $image (@vmlinuz) {
619 # search for kernel initrd file
622 $initrd =~ s/vmlinuz/initrd\.img/;
624 $initrd2 =~ s/\.img//;
627 print MYFH_NEW 'image = ' . $image . "\n";
628 if($opt_v) { print 'image = ' . $image . "\n"; }
631 print MYFH_NEW "\t" . 'label = "Linux"' . "\n";
632 if($opt_v) { print "\t" . 'label = "Linux"' . "\n"; }
635 print MYFH_NEW "\t" . 'label = "Linux Old"' . "\n";
636 if($opt_v) { print "\t" . 'label = "Linux Old"' . "\n"; }
639 print MYFH_NEW "\t" . 'read-only' . "\n";
640 if($opt_v) { print "\t" . 'read-only' . "\n"; }
641 print MYFH_NEW "#\t" . 'restricted' . "\n";
642 if($opt_v) { print "#\t" . 'restricted' . "\n"; }
643 print MYFH_NEW "#\t" . 'alias = ' . "$nr2" . "\n";
644 if($opt_v) { print "#\t" . 'alias = ' . "$nr2" . "\n"; }
645 print MYFH_NEW "#\t" . 'optional' . "\n";
646 if($opt_v) { print "#\t" . 'optional' . "\n"; }
649 print MYFH_NEW "\t" . 'initrd = ' . $initrd . "\n";
650 if($opt_v) { print "\t" . 'initrd = ' . $initrd . "\n"; }
652 elsif (-e $initrd2) {
653 print MYFH_NEW "\t" . 'initrd = ' . $initrd2 . "\n";
654 if($opt_v) { print "\t" . 'initrd = ' . $initrd2 . "\n"; }
657 if($opt_v) { print "W: initrd $initrd could not be found!\n" }
661 if($opt_v) { print "\n"; }
670 print "No images '/boot/vmlinuz*' found!\n";
671 if($opt_v) { print "\n"; }
673 elsif( not $opt_v ) {
674 print "$nr images '/boot/vmlinuz*' found.\n";
676 return ($nr > 0); # if =0 this is an error
679 sub write_imagelinks_config {
686 # append to new lilo.conf
687 open(MYFH_NEW, ">> $liloconfnew") or die "Cannot open file: $!";
689 # search for kernel image files
690 my @vmlinuz = readpipe("/bin/ls -t -1 /vmlinuz /vmlinuz.old 2>/dev/null");
692 # create some lines for each kernel image
694 foreach $image (@vmlinuz) {
695 # search for kernel initrd file
698 $initrd =~ s/vmlinuz/initrd\.img/;
701 print MYFH_NEW 'image = ' . $image . "\n";
702 if($opt_v) { print 'image = ' . $image . "\n"; }
705 print MYFH_NEW "\t" . 'label = "Linux"' . "\n";
706 if($opt_v) { print "\t" . 'label = "Linux"' . "\n"; }
709 print MYFH_NEW "\t" . 'label = "Linux Old"' . "\n";
710 if($opt_v) { print "\t" . 'label = "Linux Old"' . "\n"; }
714 print MYFH_NEW "\t" . '#root = ' . $root_dev . "\n";
715 if($opt_v) { print "\t" . '#root = ' . $root_dev . "\n"; }
716 print MYFH_NEW "\t" . 'root = "' . $root_id . '"' . "\n";
717 if($opt_v) { print "\t" . 'root = "' . $root_id . '"' . "\n"; }
720 print MYFH_NEW "\t" . 'root = ' . $root_dev . "\n";
721 if($opt_v) { print "\t" . 'root = ' . $root_dev . "\n"; }
724 print MYFH_NEW "\t" . 'read-only' . "\n";
725 if($opt_v) { print "\t" . 'read-only' . "\n"; }
726 print MYFH_NEW "#\t" . 'restricted' . "\n";
727 if($opt_v) { print "#\t" . 'restricted' . "\n"; }
728 print MYFH_NEW "#\t" . 'alias = ' . "$nr2" . "\n";
729 if($opt_v) { print "#\t" . 'alias = ' . "$nr2" . "\n"; }
730 print MYFH_NEW "#\t" . 'optional' . "\n";
731 if($opt_v) { print "#\t" . 'optional' . "\n"; }
734 print MYFH_NEW "\t" . 'initrd = ' . $initrd . "\n";
735 if($opt_v) { print "\t" . 'initrd = ' . $initrd . "\n"; }
738 if($opt_v) { print "W: initrd $initrd could not be found!\n" }
742 if($opt_v) { print "\n"; }
751 print "No image symlinks '/vmlinuz*' found!\n";
752 if($opt_v) { print "\n"; }
754 elsif( not $opt_v ) {
755 print "$nr image symlinks '/vmlinuz*' found.\n";
757 return ($nr > 0); # if =0 this is an error
767 liloconfig - create new lilo.conf file (with diskid and uuid)
771 B<liloconfig> [B<-h>] [B<-v>] [B<-f>] [B<-u>] [B<lilo.conf>]
775 liloconfig is an simple program for creating a new lilo.conf file.
776 After creating the new configuration file you must execute '/sbin/lilo'.
778 liloconfig use the lilo.example.conf file as template. In the final
779 lilo.conf file you find many useful comments for custom changes.
781 Please pay attention about error messages if liloconfig cannot find
782 any images (/boot/vmlinuz*) oder image symlinks (/vmlinuz, /vmlinu.old).
783 Then you need to search for images by ourself and make some changes
784 in the '/etc/lilo.conf' file. Otherwise no bootloader can be installed
797 Print verbose messages.
801 Force overriding existing lilo.conf.
805 Force overriding/update of boot line in lilo.conf.
811 Lines in the configuration file /etc/lilo.conf:
813 ### LILO global section ###
818 boot = /dev/disk/by-id/ata-SAMSUNG_SV1604N_S01FJ10X999999
820 root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44"
823 menu-scheme = Wb:Yr:Wb:Wb
830 ### LILO per-image section ###
832 image = /boot/vmlinuz-3.17-trunk-686
835 #root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44"
840 initrd = /boot/initrd.img-3.17-trunk-686
842 image = /boot/vmlinuz-3.14-trunk-686
845 #root = "UUID=18843936-00f9-4df0-a373-000d05a5dd44"
850 initrd = /boot/initrd.img-3.14-trunk-686
852 =head1 COPYRIGHT and LICENSE
854 Copyright (C) 2011-2015 Joachim Wiedorn
856 This script is free software; you can redistribute it and/or modify
857 it under the terms of the GNU General Public License as published by
858 the Free Software Foundation; either version 2 of the License, or
859 (at your option) any later version.
863 B<liloconfig> was written by Joachim Wiedorn.
865 This manual page was written by Joachim Wiedorn <joodevel at joonet.de>.
869 B<lilo>(8), B<update-lilo>(8), B<lilo-uuid-diskid>(8)