Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.3
elilo
elilo.pl
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File elilo.pl of Package elilo
#!/usr/bin/perl -w # $Id: elilo.pl,v 0.21 2010/12/10 20:31:09 rw Exp $ use strict; my $C = $0; $C =~ s{^.*/}{}; my $dbg = (exists( $ENV{"ELILO_DEBUG"})) ? $ENV{"ELILO_DEBUG"} : ""; my $Edition = q(@EDITION@); my $Arch = q(@ARCH@); my $LibD = q(@LIBEXECDIR@); my $MPold = "$dbg/boot"; my $MPnew = "$dbg/boot/efi"; my $Dlibold = "$dbg$LibD/elilo"; my $Dlib = "$dbg$LibD/efi"; my $Fconf = "elilo.conf"; my $Sconf = "$dbg/etc/" . $Fconf; my $Reserved = qr(^(efi-mountpoint|vendor-directory|elilo-origin|precious))o; my %Sconf = (); my $keep = -1; my $test = 0; my $verbose = 0; my $warn = 0; my $optional = 1; my $MP = ""; # Mount-Point for EFI/FAT partition my $VD = "SuSE"; # vendor-specific directory in $MP/efi my $D = ""; # will be $MP.$VD my %Labels = (); my $Disclaimer = <<EoD; # This file has been transformed by /sbin/elilo. # Please do NOT edit here -- edit /etc/elilo.conf instead! # Otherwise your changes will be lost e.g. during kernel-update. # EoD $| = 1; sub Version() { my $v = q($Revision: 0.21 $ ); $v =~ s/^\$ Rev.*:\ ([0-9.]+)\ \$\ /$1/x; $v .= " (part of elilo-$Edition)" if ( $Edition ne "\@EDITION\@" ); print "$C version $v\n"; exit( 0 ); } sub Info ($$) { print STDERR $_[1] if ( $verbose >= $_[0] ); } sub Warn ($) { print STDERR "$C: Warning: $_[0]"; $warn ++; } sub Panic ($$) { print STDERR "$C: $_[1]"; exit( $_[0]) if ( $_[0] ); $warn ++; print STDERR "...trying to proceed anyway!\n"; } sub Parse ($) { my( $f) = @_; my %r = (); Info( 3, "### Parse '$f'\n"); open( IN, "< $f") || return( %r ); # fixme: add failure-detection while ( <IN> ) { chomp; next unless ( m/$Reserved\s*(?:\=\s*(.+))?\s*$/xo ); $r{$1} = (defined($2)) ? $2 : "true"; Info( 3, ">>> $1 = '$r{$1}'\n"); } close( IN); return( %r ); } sub Transfer ($$) { my( $in, $dir) = @_; my( $out, $tmp, $c, @f, %f, $opt); my $default_label = ""; my $default_loc; my $image = ""; my @Out = (); $out = "$dir/$Fconf"; $tmp = "$out.tmp"; $opt = $optional; open( IN, "< $in") || Panic(1, "$in: failed to open: $!\n"); Info( 1, "## filter '$in' to"); if ( ! $test ) { Info( 1, " '$tmp'\n"); open(OUT, "> $tmp") || Panic( 1, "$tmp: failed to create: $!\n"); push @Out, $Disclaimer; } elsif ( $verbose >= 2 ) { Info( 1, " STDOUT\n"); open( OUT, ">&STDOUT"); push @Out, $Disclaimer unless ( $verbose < 3 ); } else { Info( 1, " /dev/null\n"); open( OUT, ">/dev/null"); } while ( <IN> ) { next if ( m/$Reserved/xo ); if ( m{^\s*(?:image|initrd|vmm)\s*=\s*} ) { chomp; s{^(\s*(image|initrd|vmm)\s*=\s*)(/\S+/)?([^/\s]+)\s*$}{$1$4}; my( $t, $p, $f) = ($2, $3, $4); #Info( 0, "$C: $in: $.: t=$t p=$p f=$f\n"); $_ .= "\n"; if ( ! defined( $p) ) { $p = "/boot/"; } $image = "" if ( $t eq "image" ); if ( ! defined( $f) ) { Warn( "$in: $.: invalid file-specification\n" . ">> $_"); $c++; } elsif ( $opt && ! -r "$dbg$p$f" ) { Info( 0, "$C: $in: $.: missing optional '$p$f' skipped\n"); } elsif ( exists( $f{$f}) ) { $image = $dbg . "$p$f" if ( $t eq "image" ); Info( 3, "$in: $.: file duplication skipped (previous: $f{$f})\n" . ">> $_"); } else { $image = $dbg . "$p$f" if ( $t eq "image" ); push @f, $dbg . "$p$f"; $f{$f} = $.; } } elsif ( $image && m{^(\s*description\s*=\s*")([^"]+)(".*)$} ) { my( $p, $d, $s) = ($1, $2, $3); my $t = ""; if ( $d =~ m{\%L} ) { if ( -l $image ) { ($t = readlink( $image)) =~ s{^vmlinuz-}{}; } else { #($t = $image) =~ s{^.*vmlinux-}{}; $t = "no symlink"; } Info( 2, " \%L => '$t'\n"); $d =~ s{\%L}{$t}; } elsif ( $d =~ m{\%G} ) { my $cmd = "/sbin/get_kernel_version"; if ( -x $cmd ) { chomp( $t = `$cmd $image`); } else { $t = ""; } $d =~ s{\%G}{$t}; Info( 2, " \%G => '$t'\n"); } $_ = $p . $d . $s . "\n"; } elsif (m{^(\s*label\s*=\s*)(\S+)}) { my ($pre, $label) = ($1, $2); if (exists $Labels{$label}) { my $t = 1; my $l = $label; while ( exists $Labels{$l} ) { $l = sprintf "%s.%d", $label, $t++; } Warn( "duplicate label '$label', replaced with '$l'\n"); $label = $l; $_ = $pre . $l . "\n"; } $Labels{$label} = 1; } elsif (m{^\s*default\s*=\s*(\S+)}) { $default_label = $1; $default_loc = $#Out + 1; } elsif (m{^\s*read-only\s*$}) { $_ = "#read-only # Deprecated!" . " (Add comment in '$Sconf' to overrule.)" . "\n"; Info( 2, " $in: $.: deprecated 'read-only' ignored.\n"); } elsif (m{^\s*relocatable\s*$} && $Arch =~ m{86}) { $_ = "#relocatable # Unsupported on this architecture!\n" . "# (May be forced by adding a comment in '$Sconf'.)\n"; Info( 2, " $in: $.: unsupported 'relocatable' ignored.\n"); } push @Out, $_; } if ($default_label ne "" && !exists $Labels{$default_label}) { $Out[$default_loc] = "#" . $Out[$default_loc]; Warn( "undefined default label '$default_label' discarded\n"); } print OUT @Out; close( OUT); close( IN); Info( 2, "## end of $in\n") unless $test; foreach ( @f ) { if ( ! -r $_ ) { Warn( "$_: not found\n"); $c++; } } if ( $c ) { Info( 2, "> unlink( $tmp)\n"); unlink( $tmp); Panic( 2, "$in: broken references\n"); } if ( ! $test ) { Info( 1, "> unlink( $out)\n"); unlink( $out); Info( 1, "> rename( $tmp, $out)\n"); rename( $tmp, $out); # fixme: add failure-detection } return( @f ); } sub System($@) { my( $fatal, @C) = @_; my $cmd = $C[0]; foreach my $c ( @C[1..$#C] ) { if ( $c =~ /\s/ ) { $cmd .= " '$c'"; } else { $cmd .= " $c"; } } Info( 1, "> $cmd\n"); return 0 if ( $test ); system @C; if ($? == -1) { Panic( $fatal, "$C[0]: failed to execute: $!\n"); } elsif ($? & 127) { Panic( $fatal, sprintf( "$C[0]: died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without')); } elsif ( $? >> 8 != 0 ) { Panic( $fatal, "$C[0]: failed\n"); } } sub Purge($) { my( $d) = @_; if ( $keep > 0) { Info( 1, "## skip removal of old files from '$d'\n"); return 0; } Info( 1, "## remove old files from '$d'\n"); my @F = glob( "$d/*"); foreach my $f ( @F ) { next unless ( $f =~ m{.*/((vm|)linu(x|z)|initrd)(|[-.]\S+)$} ); Info( 1, "> rm $f\n"); unlink( $f) unless ($test); } } sub Install($$$$) { my( $f, $o, $s, $d) = @_; my @C = ( "install", $o, $s, $d); if ( $o eq "-p" ) { @C = ( "cp", "--preserve=timestamps", $s, $d); } System( $f, @C); } sub InstallFPSWA($) { my ( $d) = @_; my $Dfpswa = $Dlib; $d .= "/efi/Intel Firmware"; $Dfpswa = $Dlibold unless ( -r "$Dfpswa/fpswa.efi" ); return 0 unless ( -r "$Dfpswa/fpswa.efi" ); my $head = "## fpswa: Floating Point Software Assist\n"; if ( -d $d && -r "$d/fpswa.efi" ) { # check, if we need to update and failing that do nothing?! my $c = "$Dfpswa/fpswa-cmp-version"; if ( -x $c ) { my $chk = `$c "$d/fpswa.efi" "$Dfpswa/fpswa.efi"`; if ( $chk =~ /older/ ) { Info( 1, $head . "## Update '$d/fpswa.efi'.\n"); Info( 2, "## $chk"); Install( 0, "-p", "$Dfpswa/fpswa.efi", $d); } else { Info( 1, $head . "## Do NOT update '$d/fpswa.efi'.\n"); Info( 2, "## $chk"); } } else { use File::Compare; if ( compare( "$d/fpswa.efi", "$Dfpswa/fpswa.efi") == 0 ) { Info( 2, $head . "## Already installed.\n"); } else { Info( 1, $head . "## Unable to compare versions.\n" . "## Installation skipped!\n"); } } } else { Info( 1, $head . "## Install 'fpswa.efi' to '$d'.\n"); System( 0, "mkdir", $d) unless ( -d $d ); Install( 0, "-p", "$Dfpswa/fpswa.efi", $d); } } sub isMP($) { my ( $d) = @_; my @I = ("/proc/mounts", "/etc/mtab"); Info( 3, "### isMP($d):"); foreach my $f ( @I ) { open( IN, "< $f") || next; while ( <IN> ) { chomp; my @F = split; if ( $F[1] eq $d ) { Info( 3, " found in '$f' line $. => true\n"); close( IN); return( 1); } } close( IN); Info( 3, " not found in '$f' => false\n"); return( 0); } Info( 3, " not found in [" . join( ", ", @I) . "] => false\n"); return( 0); } { use Getopt::Long; use Pod::Usage; $Getopt::Long::debug = 0; $Getopt::Long::ignorecase = 0; $Getopt::Long::bundling = 1; $Getopt::Long::passthrough = 0; my %Opt = (); pod2usage(2) unless ( GetOptions( \%Opt, 'help|h', 'man|m', 'version|V', 'verbose|v+', 'test|t', 'keep|k', 'purge|K') && ( ! $Opt{'purge'} || ! $Opt{'keep'} ) && ! $Opt{'help'} ); Version() if ( $Opt{'version'} ); pod2usage(-exitstatus => 0, -verbose => 2) if ( $Opt{'man'} ); pod2usage(1) if ( $Opt{'help'} ); $test = 1 if ( $Opt{'test'} ); $keep = 0 if ( $Opt{'purge'} ); $keep = 1 if ( $Opt{'keep'} ); $verbose += $Opt{'verbose'} if ( $Opt{'verbose'} ); } # run-time init if ( $Arch =~ m{ARCH} ) { chomp( $Arch = qx{uname -m}); Info( 3, "### Arch: '$Arch'\n"); } if ( $Dlib =~ m{LIBEXECDIR} ) { $Dlib = "$dbg/usr/lib" . (($Arch eq "x86_64") ? "64/" : "/"); $Dlibold = $Dlib . "elilo"; $Dlib = $Dlib . "efi"; $Dlib = $Dlibold if (! -r "$Dlib/elilo.efi" && -r "$Dlibold/elilo.efi"); Info( 3, "### Dlib: '$Dlib'\n"); } # try to read variables from $Sconf %Sconf = Parse( $Sconf); # check environment if ( exists( $Sconf{"efi-mountpoint"}) ) { $MP = $dbg . $Sconf{"efi-mountpoint"}; Panic( 2, "EFI partition specification in $Sconf invalid.\n") unless ( -d $MP ); # or is it "$MP/efi"? } elsif ( -d $MPnew . "/efi/" . $VD || isMP($MPnew) ) { $MP = $MPnew; } elsif ( -d $MPold . "/efi/" . $VD ) { $MP = $MPold; } else { Info( 1, "## Neither new ($MPnew/efi/$VD) nor old ($MPold/efi/$VD)?\n"); Panic( 2, "EFI partition not found.\n"); } Info( 2, "## Mount-point '$MP'...\n"); if ( exists( $Sconf{"vendor-directory"}) ) { $VD = $Sconf{"vendor-directory"}; Info( 1, "## Don't forget: '$VD != SuSE'--NVRAM (efibootmgr) issue!\n") unless ( $VD eq "SuSE" ); } if ( exists( $Sconf{"precious"}) && $keep < 0 ) { $keep = 1; } $D = $MP . "/efi/" . $VD; Info( 1, "## Using '$D'...\n"); System( 2, "mkdir", "-p", $D) unless ( -d $D ); if ( -r $Sconf ) { # extract kernels, etc. and write fixed .conf my @F = Transfer( $Sconf, $D); # remove old files Purge( $D); # copy stuff Info( 1, "## copy new files to '$D'\n"); unshift @F, "$Dlib/elilo.efi"; foreach ( @F ) { Install( 0, "-p", $_, $D); } # take care of FPSWA InstallFPSWA( $MP); } elsif ( $MP eq $MPold && -r "$D/$Fconf" ) { # assume old setup with only '/vmlinuz' and '/initrd' Install( 2, "-p", "$Dlib/elilo.efi", $D); InstallFPSWA( $MP); } elsif ( $MP eq $MPold ) { Panic( 2, "$D/$Fconf: not found\n"); } elsif ( ! -e $Sconf ) { Panic( 2, "$Sconf: not found\n"); } else { Panic( 2, "$Sconf: not readable\n"); } if ( $warn > 0 ) { Panic( 1, sprintf("%d warning%s encountered.\n", $warn, ($warn==1)?"":"s")); } exit( 0); __END__ =head1 NAME elilo - Installer for the EFI Linux Loader =head1 SYNOPSIS /sbin/elilo [options] Options: -k --keep don't purge old files -t --test test only -v --verbose increase verbosity -h --help brief help message --man full documentation -V --version display version =head1 OPTIONS =over 8 =item B<--test> Test only. Do not really write anything, no new boot configuration nor kernel/initrd images. Use together with B<-v> to find out what B<elilo> is about to do. =item B<--verbose> Increase level of verbosity. =item B<--help> Print a brief help message and exits. =item B<--man> Prints the manual page and exits. =item B<--version> Prints the version information and exits. =back =head1 DESCRIPTION This program will perform all steps to transfer the necessary parts to the appropriate locations... =head1 LIMITATIONS For now, I<all> image-entries are treated as "optional" in order to more closely match the behavior of the real loader (i.e. C<elilo.efi>), which silently ignores missing files while reading the configuration. This may be considered a bug by experienced B<LILO> users, where only those specifically marked as such are treated that way. It is planned to introduce keywords like C<mandatory> and C<optional> in future releases though. =head1 SEE ALSO /usr/share/doc/packages/elilo =cut
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor