#!/usr/bin/perl -w
my
@bootconfig
= [];
my
$debug
= 0;
my
$bootloader
;
my
%params
;
GetOptions(
\
%params
,
"bootloader-probe"
,
"arch-probe:s"
,
"bootloader|b=s"
,
"config_file=s"
,
"add-kernel|a=s"
,
"remove-kernel|r=s"
,
"update-kernel|u=s"
,
"title=s"
,
"args=s"
,
"remove-args=s"
,
"initrd=s"
,
"root=s"
,
"savedefault=s"
,
"position=s"
,
"info|i=s"
,
"debug|d=i"
,
"set-default=s"
,
"make-default"
,
"force"
,
"boot-once"
,
"install"
,
"default"
,
"help"
,
"man"
,
"xen"
,
"xenhyper|xh=s"
,
"xenhyper-args|xha=s"
,
"update-xenhyper=s"
,
);
&usage
if
( !
%params
||
defined
$params
{help} );
sub
detect_architecture {
my
$arch_style
=
shift
||
'uname'
;
my
$arch
;
if
(
$arch_style
eq
'linux'
) {
$arch
= `uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/s390x/s390/ -e s/parisc64/parisc/`;
chomp
$arch
;
}
elsif
(
$arch_style
eq
'gentoo'
) {
$arch
= `uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/ -e s/sparc.*/sparc/ -e s/parisc.*/hppa/`;
chomp
$arch
;
}
else
{
$arch
= `uname -m`;
chomp
$arch
;
}
return
$arch
;
}
sub
detect_bootloader {
return
detect_bootloader_from_conf(
@_
)
|| detect_bootloader_from_mbr(
@_
);
}
sub
detect_bootloader_from_conf {
my
@boot_loader
= ();
my
%boot_list
= (
grub
=>
'/boot/grub/menu.lst'
,
lilo
=>
'/etc/lilo.conf'
,
elilo
=>
'/etc/elilo.conf'
,
yaboot
=>
'/etc/yaboot.conf'
);
foreach
my
$key
(
sort
keys
%boot_list
) {
if
( -f
$boot_list
{
$key
} ) {
push
(
@boot_loader
,
$key
);
}
}
if
(
wantarray
() ) {
return
@boot_loader
;
}
elsif
(
@boot_loader
== 1 ) {
return
pop
(
@boot_loader
);
}
else
{
return
undef
;
}
}
sub
detect_bootloader_from_mbr {
my
@filelist
=
@_
;
my
@boot_loader
= ();
my
%map
= (
"GRUB"
=>
'grub'
,
"LILO"
=>
'lilo'
,
"EFI"
=>
'elilo'
,
"yaboot"
=>
'yaboot'
,
);
if
( !
@filelist
&&
opendir
( DIRH,
"/sys/block"
) ) {
@filelist
=
grep
{ /^[sh]d.$/ }
readdir
(DIRH);
closedir
(DIRH);
}
foreach
(
@filelist
) {
if
( -b
"/dev/$_"
) {
my
$strings
= `dd
if
=/dev/
$_
bs=512 count=1 2>/dev/null | strings`;
foreach
my
$loader
(
keys
%map
) {
if
(
$strings
=~ /
$loader
/ms ) {
push
@boot_loader
,
$map
{
$loader
};
}
}
}
}
if
(
wantarray
() ) {
return
@boot_loader
;
}
elsif
(
@boot_loader
== 1 ) {
return
pop
@boot_loader
;
}
else
{
return
undef
;
}
}
sub
_info_grub {
return
undef
unless
&_check_config
();
my
@config
=
@bootconfig
;
@config
=
grep
( !/^
my
%matches
= (
default
=>
'^\s*default\s*\=*\s*(\S+)'
,
timeout
=>
'^\s*timeout\s*\=*\s*(\S+)'
,
fallback
=>
'^\s*fallback\s*\=*\s*(\S+)'
,
kernel
=>
'^\s*kernel\s+(\S+)'
,
root
=>
'^\s*kernel\s+.*\s+root=(\S+)'
,
args
=>
'^\s*kernel\s+\S+\s+(.*)\n'
,
boot
=>
'^\s*root\s+(.*)'
,
initrd
=>
'^\s*initrd\s+(.*)'
,
savedefault
=>
'^\s*savedefault\s+(.*)'
,
module
=>
'^\s*module\s+(.+)'
,
);
my
@sections
;
my
$index
= 0;
foreach
(
@config
) {
if
(
$_
=~ /^\s
*title
\s+(.*)/i ) {
$index
++;
$sections
[
$index
]{title} = $1;
}
foreach
my
$key
(
keys
%matches
) {
if
(
$_
=~ /
$matches
{
$key
}/i ) {
$key
.=
'2'
if
exists
$sections
[
$index
]{
$key
};
$sections
[
$index
]{
$key
} = $1;
if
(
$key
eq
'args'
) {
$sections
[
$index
]{
$key
} =~ s/root=\S+\s*//i;
delete
$sections
[
$index
]{
$key
}
if
(
$sections
[
$index
]{
$key
} !~ /\S/ );
}
}
}
}
if
( !(
defined
$sections
[0]{
'default'
} ) ) {
$sections
[0]{
'default'
} =
'0'
;
}
elsif
(
$sections
[0]{
'default'
} =~ m/^saved$/i ) {
open
( DEFAULT_FILE,
'/boot/grub/default'
)
||
warn
(
"ERROR: cannot read grub default file.\n"
) &&
return
undef
;
my
@default_config
= <DEFAULT_FILE>;
close
(DEFAULT_FILE);
$default_config
[0] =~ /^(\d+)/;
$sections
[0]{
'default'
} = $1;
}
return
@sections
;
}
sub
set_default_grub {
my
$newdefault
=
shift
;
return
undef
unless
defined
$newdefault
;
return
undef
unless
&_check_config
();
my
@config
=
@bootconfig
;
my
@sections
=
&_info
();
if
(
$newdefault
!~ /^\d+$/ ) {
$newdefault
=
&_lookup
(
$newdefault
);
}
my
$kcount
=
$#sections
- 1;
if
( ( !
defined
$newdefault
)
|| (
$newdefault
< 0 )
|| (
$newdefault
>
$kcount
) )
{
warn
"ERROR: Enter a default between 0 and $kcount.\n"
;
return
undef
;
}
foreach
my
$index
( 0 ..
$#config
) {
if
(
$config
[
$index
] =~ /(^\s
*default
\s*\=*\s*)\d+/i ) {
$config
[
$index
] =
"$1$newdefault # set by $0\n"
;
last
;
}
elsif
(
$config
[
$index
] =~ /^\s
*default
\s*\=*\s
*saved
/i ) {
my
@default_config
;
my
$default_config_file
=
'/boot/grub/default'
;
open
( DEFAULT_FILE,
$default_config_file
)
||
warn
(
"ERROR: cannot open default file.\n"
) &&
return
undef
;
@default_config
= <DEFAULT_FILE>;
close
(DEFAULT_FILE);
$default_config
[0] =
"$newdefault\n"
;
open
( DEFAULT_FILE,
">$default_config_file"
)
||
warn
(
"ERROR: cannot open default file.\n"
) &&
return
undef
;
print
DEFAULT_FILE
join
(
""
,
@default_config
);
close
(DEFAULT_FILE);
last
;
}
}
@bootconfig
=
@config
;
}
sub
add_grub {
my
%param
=
@_
;
print
(
"Adding kernel.\n"
)
if
&debug
() > 1;
if
( !
defined
$param
{
'add-kernel'
} || !
defined
$param
{
'title'
} ) {
warn
"ERROR: kernel path (--add-kernel), title (--title) required.\n"
;
return
undef
;
}
elsif
( !( -f
"$param{'add-kernel'}"
) ) {
warn
"ERROR: kernel $param{'add-kernel'} not found!\n"
;
return
undef
;
}
elsif
(
defined
$param
{
'initrd'
} && !( -f
"$param{'initrd'}"
) ) {
warn
"ERROR: initrd $param{'initrd'} not found!\n"
;
return
undef
;
}
return
undef
unless
&_check_config
();
my
@sections
=
&_info
();
if
(
defined
&_lookup
(
$param
{title} ) ) {
warn
(
"WARNING: Title already exists.\n"
);
if
(
defined
$param
{force} ) {
&remove
(
$param
{title} );
}
else
{
return
undef
;
}
}
my
@config
=
@bootconfig
;
@sections
=
&_info
();
my
$default
=
&get_default
();
$default
++;
foreach
my
$p
(
'args'
,
'root'
,
'boot'
,
'savedefault'
) {
if
( !
defined
$param
{
$p
} ) {
$param
{
$p
} =
$sections
[
$default
]{
$p
};
}
}
if
(
$sections
[
$default
]{
'kernel'
} !~ /^\/boot/ ) {
$param
{
'add-kernel'
} =~ s/^\/boot//;
$param
{
'initrd'
} =~ s/^\/boot//
unless
!
defined
$param
{
'initrd'
};
}
my
@newkernel
;
push
(
@newkernel
,
"title\t$param{title}\n"
)
if
defined
$param
{title};
push
(
@newkernel
,
"\troot $param{boot}\n"
)
if
defined
$param
{boot};
my
$line
;
if
(
defined
$param
{xen} ) {
if
(
defined
$param
{
'xenhyper'
} ) {
$line
=
"\tkernel $param{'xenhyper'}"
;
$line
.=
" $param{'xenhyper-args'}"
if
defined
$param
{
'xenhyper-args'
};
push
(
@newkernel
,
"$line\n"
);
}
else
{
$line
=
"\tkernel $sections[$default]{kernel}"
;
$line
.=
" $sections[$default]{root}"
if
defined
$sections
[
$default
]{root};
$line
.=
" $sections[$default]{args}"
if
defined
$sections
[
$default
]{args};
push
(
@newkernel
,
"$line\n"
);
}
$line
=
"\tmodule $param{'add-kernel'}"
if
defined
$param
{
'add-kernel'
};
$line
.=
" root=$param{root}"
if
defined
$param
{root};
$line
.=
" $param{args}"
if
defined
$param
{args};
push
(
@newkernel
,
"$line\n"
);
push
(
@newkernel
,
"\tmodule $param{initrd}\n"
)
if
defined
$param
{initrd};
}
else
{
$line
=
"\tkernel $param{'add-kernel'}"
if
defined
$param
{
'add-kernel'
};
$line
.=
" root=$param{root}"
if
defined
$param
{root};
$line
.=
" $param{args}"
if
defined
$param
{args};
push
(
@newkernel
,
"$line\n"
);
push
(
@newkernel
,
"\tinitrd $param{initrd}\n"
)
if
defined
$param
{initrd};
}
push
(
@newkernel
,
"\tsavedefault $param{savedefault}\n"
)
if
defined
$param
{savedefault};
push
(
@newkernel
,
"\n"
);
if
( !
defined
$param
{position} ||
$param
{position} !~ /end|\d+/ ) {
$param
{position} = 0;
}
my
@newconfig
;
if
(
$param
{position} =~ /end/ ||
$param
{position} >=
$#sections
) {
$param
{position} =
$#sections
;
push
(
@newconfig
,
@config
);
if
(
$newconfig
[
$#newconfig
] =~ /\S/ ) {
push
(
@newconfig
,
"\n"
);
}
push
(
@newconfig
,
@newkernel
);
}
else
{
my
$index
= 0;
foreach
(
@config
) {
if
(
$_
=~ /^\s
*title
/i ) {
if
(
$index
==
$param
{position} ) {
push
(
@newconfig
,
@newkernel
);
}
$index
++;
}
push
(
@newconfig
,
$_
);
}
}
@bootconfig
=
@newconfig
;
if
(
defined
$param
{
'make-default'
} ||
defined
$param
{
'boot-once'
} ) {
&set_default
(
$param
{position} );
}
print
"Added: $param{'title'}.\n"
;
}
sub
update_grub {
my
%params
=
@_
;
print
(
"Updating kernel.\n"
)
if
&debug
() > 1;
if
( !
defined
$params
{
'update-kernel'
} && !
defined
$params
{
'xenhyper-args'
}
|| ( !
defined
$params
{
'args'
} && !
defined
$params
{
'remove-args'
}
&& !
defined
$params
{
'xenhyper-args'
} ) )
{
warn
"ERROR: kernel position or title (--update-kernel) and args (--args or --remove-args) required.\n"
;
return
undef
;
}
return
undef
unless
&_check_config
();
my
@config
=
@bootconfig
;
my
@sections
=
&_info
();
if
(
$params
{
'update-kernel'
} !~ /^\d+$/ ) {
$params
{
'update-kernel'
} =
&_lookup
(
$params
{
'update-kernel'
} );
}
my
$kcount
=
$#sections
- 1;
if
(
$params
{
'update-kernel'
} !~ /^\d+$/
||
$params
{
'update-kernel'
} < 0
||
$params
{
'update-kernel'
} >
$kcount
)
{
warn
"ERROR: Enter a default between 0 and $kcount.\n"
;
return
undef
;
}
my
$kregex
=
'(^\s*kernel\s+\S+)(.*)'
;
if
( !
defined
$params
{
'update-xenhyper'
} &&
defined
$params
{
'xen'
} )
{
$kregex
=
'(^\s*module\s+\S+vmlinuz\S+)(.*)'
if
defined
$params
{
'xen'
};
}
my
$index
= -1;
foreach
(
@config
) {
if
(
$_
=~ /^\s
*title
/i ) {
$index
++;
}
if
(
$index
==
$params
{
'update-kernel'
} ) {
if
(
$_
=~ /
$kregex
/i ) {
my
$kernel
= $1;
my
$args
= $2;
$args
=~ s/\s+
$params
{
'remove-args'
}(\=\S+|\s+|$)/ /ig
if
defined
$params
{
'remove-args'
};
if
(
defined
$params
{
'args'
} ||
defined
$params
{
'xenhyper-args'
} ) {
$params
{
'args'
} =
$params
{
'xenhyper-args'
}
if
defined
$params
{
'xenhyper-args'
};
my
$base_arg
=
$params
{
'args'
};
$base_arg
=~ s/\=.*//;
$args
=~ s/\s+
$base_arg
(\=\S+|\s+|$)/ /ig;
$args
=
$args
.
" "
.
$params
{
'args'
};
}
if
(
$_
eq
$kernel
.
$args
.
"\n"
) {
warn
"WARNING: No change made to args.\n"
;
return
undef
;
}
else
{
$_
=
$kernel
.
$args
.
"\n"
;
}
next
;
}
}
}
@bootconfig
=
@config
;
}
sub
install_grub {
my
$device
;
warn
"Re-installing grub is currently unsupported.\n"
;
warn
"If you really need to re-install grub, use 'grub-install <device>'.\n"
;
return
undef
;
}
sub
install_lilo {
system
(
"/sbin/lilo"
);
if
( $? != 0 ) {
warn
(
"ERROR: Failed to run lilo.\n"
) &&
return
undef
;
}
return
1;
}
sub
boot_once_lilo {
my
$label
=
shift
;
return
undef
unless
defined
$label
;
if
(
system
(
"lilo"
,
"-R"
,
"$label"
) ) {
warn
(
"ERROR: Failed to set boot-once.\n"
) &&
return
undef
;
}
return
1;
}
sub
install_elilo {
system
(
"/usr/sbin/elilo"
);
if
( $? != 0 ) {
warn
(
"ERROR: Failed to run elilo.\n"
) &&
return
undef
;
}
return
1;
}
sub
boot_once_elilo {
my
$label
=
shift
;
return
undef
unless
defined
$label
;
&read
(
'/etc/elilo.conf'
);
my
@config
=
@bootconfig
;
if
( !
grep
( /^checkalt/i,
@config
) ) {
warn
(
"ERROR: Failed to set boot-once.\n"
);
warn
(
"Please add 'checkalt' to global config.\n"
);
return
undef
;
}
my
@sections
=
&_info
();
my
$position
=
&_lookup
(
$label
);
$position
++;
my
$efiroot
= `
grep
^EFIROOT /usr/sbin/elilo | cut -d
'='
-f 2`;
chomp
(
$efiroot
);
my
$kernel
=
$efiroot
.
$sections
[
$position
]{kernel};
my
$root
=
$sections
[
$position
]{root};
my
$args
=
$sections
[
$position
]{args};
if
(
system
(
"eliloalt"
,
"-s"
,
"$kernel root=$root $args"
) ) {
warn
(
"ERROR: Failed to set boot-once.\n"
);
warn
(
"1) Check that EFI var support is compiled into kernel.\n"
);
warn
(
"2) Verify eliloalt works. You may need to patch it to support sysfs EFI vars.\n"
);
return
undef
;
}
return
1;
}
sub
install_yaboot {
print
(
"Not installing bootloader.\n"
);
print
(
"Depending on your arch you may need to run ybin.\n"
);
return
1;
}
sub
read
{
my
$config_file
=
shift
;
print
(
"Reading $config_file.\n"
)
if
debug() > 1;
open
( CONFIG,
"$config_file"
)
||
warn
(
"ERROR: Can't open $config_file.\n"
) &&
return
undef
;
@bootconfig
= <CONFIG>;
close
(CONFIG);
print
(
"Current config:\n @bootconfig"
)
if
&debug
() > 4;
print
(
"Closed $config_file.\n"
)
if
&debug
() > 2;
return
1;
}
sub
write
{
my
$config_file
=
shift
;
my
@config
=
@bootconfig
;
return
undef
unless
&_check_config
();
print
(
"Writing $config_file.\n"
)
if
&debug
() > 1;
print
join
(
""
,
@config
)
if
&debug
() > 4;
if
( -w
$config_file
) {
system
(
"cp"
,
"$config_file"
,
"$config_file.bak.boottool"
);
if
( $? != 0 ) {
warn
"ERROR: Cannot backup $config_file.\n"
;
return
undef
;
}
else
{
print
"Backed up config to $config_file.bak.boottool.\n"
;
}
open
( CONFIG,
">$config_file"
)
||
warn
(
"ERROR: Can't open config file.\n"
) &&
return
undef
;
print
CONFIG
join
(
""
,
@config
);
close
(CONFIG);
return
0;
}
else
{
print
join
(
""
,
@config
)
if
&debug
() > 2;
warn
"WARNING: You do not have write access to $config_file.\n"
;
return
1;
}
}
sub
_info {
return
&_info_grub
()
if
(
$bootloader
eq
'grub'
);
return
undef
unless
&_check_config
();
my
@config
=
@bootconfig
;
@config
=
grep
( !/^
my
%matches
= (
default
=>
'^\s*default[\s+\=]+(\S+)'
,
timeout
=>
'^\s*timeout[\s+\=]+(\S+)'
,
title
=>
'^\s*label[\s+\=]+(\S+)'
,
root
=>
'^\s*root[\s+\=]+(\S+)'
,
args
=>
'^\s*append[\s+\=]+(.*)'
,
initrd
=>
'^\s*initrd[\s+\=]+(\S+)'
,
);
my
@sections
;
my
$index
= 0;
foreach
(
@config
) {
if
(
$_
=~ /^\s*(image|other)[\s+\=]+(\S+)/i ) {
$index
++;
$sections
[
$index
]{
'kernel'
} = $2;
}
foreach
my
$key
(
keys
%matches
) {
if
(
$_
=~ /
$matches
{
$key
}/i ) {
$sections
[
$index
]{
$key
} = $1;
$sections
[
$index
]{
$key
} =~ s/\"|\
'//g if ( $key eq '
args' );
}
}
}
if
( !(
defined
$sections
[0]{
'default'
} ) ) {
$sections
[0]{
'default'
} =
'0'
;
}
elsif
(
$sections
[0]{
'default'
} !~ m/^\d+$/ ) {
foreach
my
$index
( 1 ..
$#sections
) {
if
(
$sections
[
$index
]{
'title'
} eq
$sections
[0]{
'default'
} ) {
$sections
[0]{
'default'
} =
$index
- 1;
last
;
}
}
}
if
(
$sections
[0]{
'default'
} !~ m/^\d+$/ ) {
$sections
[0]{
'default'
} = 0;
}
return
@sections
;
}
sub
get_default {
print
(
"Getting default.\n"
)
if
&debug
() > 1;
return
undef
unless
&_check_config
();
my
@sections
=
&_info
();
my
$default
=
$sections
[0]{
'default'
};
$default
= 0 +
$default
;
return
(
$default
);
}
sub
set_default {
my
$newdefault
=
shift
;
return
&set_default_grub
(
$newdefault
)
if
(
$bootloader
eq
'grub'
);
print
(
"Setting default.\n"
)
if
&debug
() > 1;
return
undef
unless
defined
$newdefault
;
return
undef
unless
&_check_config
();
my
@config
=
@bootconfig
;
my
@sections
=
&_info
();
if
(
$newdefault
!~ /^\d+$/ ) {
$newdefault
=
&_lookup
(
$newdefault
);
}
my
$kcount
=
$#sections
- 1;
if
( ( !
defined
$newdefault
)
|| (
$newdefault
< 0 )
|| (
$newdefault
>
$kcount
) )
{
warn
"ERROR: Enter a default between 0 and $kcount.\n"
;
return
undef
;
}
$newdefault
=
$sections
[ ++
$newdefault
]{title};
foreach
my
$index
( 0 ..
$#config
) {
if
(
$config
[
$index
] =~ /^\s
*default
/i ) {
$config
[
$index
] =
"default=$newdefault # set by $0\n"
;
last
;
}
}
@bootconfig
=
@config
;
}
sub
add {
my
%param
=
@_
;
return
&add_grub
(
%param
)
if
(
$bootloader
eq
'grub'
);
print
(
"Adding kernel.\n"
)
if
&debug
() > 1;
if
( !
defined
$param
{
'add-kernel'
} || !
defined
$param
{
'title'
} ) {
warn
"ERROR: kernel path (--add-kernel), title (--title) required.\n"
;
return
undef
;
}
elsif
( !( -f
"$param{'add-kernel'}"
) ) {
warn
"ERROR: kernel $param{'add-kernel'} not found!\n"
;
return
undef
;
}
elsif
(
defined
$param
{
'initrd'
} && !( -f
"$param{'initrd'}"
) ) {
warn
"ERROR: initrd $param{'initrd'} not found!\n"
;
return
undef
;
}
return
undef
unless
&_check_config
();
$param
{title} =~ s/\s+//g;
$param
{title} =
substr
(
$param
{title}, 0, 15 )
if
length
(
$param
{title} ) > 15;
my
@sections
=
&_info
();
if
(
defined
&_lookup
(
$param
{title} ) ) {
warn
(
"WARNING: Title already exists.\n"
);
if
(
defined
$param
{force} ) {
&remove
(
$param
{title} );
}
else
{
return
undef
;
}
}
my
@config
=
@bootconfig
;
@sections
=
&_info
();
my
$default
=
&get_default
();
$default
++;
foreach
my
$p
(
'args'
,
'root'
) {
if
( !
defined
$param
{
$p
} ) {
$param
{
$p
} =
$sections
[
$default
]{
$p
};
}
}
if
(
$sections
[
$default
]{
'kernel'
} !~ /^\/boot/ ) {
$param
{
'add-kernel'
} =~ s/^\/boot//;
$param
{
'initrd'
} =~ s/^\/boot//
unless
( !
defined
$param
{
'initrd'
} );
}
my
@newkernel
;
push
(
@newkernel
,
"image=$param{'add-kernel'}\n"
,
"\tlabel=$param{title}\n"
);
push
(
@newkernel
,
"\tappend=\"$param{args}\"\n"
)
if
defined
$param
{args};
push
(
@newkernel
,
"\tinitrd=$param{initrd}\n"
)
if
defined
$param
{initrd};
push
(
@newkernel
,
"\troot=$param{root}\n"
)
if
defined
$param
{root};
push
(
@newkernel
,
"\tread-only\n\n"
);
if
( !
defined
$param
{position} ||
$param
{position} !~ /end|\d+/ ) {
$param
{position} = 0;
}
my
@newconfig
;
if
(
$param
{position} =~ /end/ ||
$param
{position} >=
$#sections
) {
$param
{position} =
$#sections
;
push
(
@newconfig
,
@config
);
if
(
$newconfig
[
$#newconfig
] =~ /\S/ ) {
push
(
@newconfig
,
"\n"
);
}
push
(
@newconfig
,
@newkernel
);
}
else
{
my
$index
= 0;
foreach
(
@config
) {
if
(
$_
=~ /^\s*(image|other)/i ) {
if
(
$index
==
$param
{position} ) {
push
(
@newconfig
,
@newkernel
);
}
$index
++;
}
push
(
@newconfig
,
$_
);
}
}
@bootconfig
=
@newconfig
;
if
(
defined
$param
{
'make-default'
} ) {
&set_default
(
$param
{position} );
}
}
sub
update {
my
%params
=
@_
;
return
&update_grub
(
%params
)
if
(
$bootloader
eq
'grub'
);
print
(
"Updating kernel.\n"
)
if
&debug
() > 1;
if
( !
defined
$params
{
'update-kernel'
}
|| ( !
defined
$params
{
'args'
} && !
defined
$params
{
'remove-args'
} ) )
{
warn
"ERROR: kernel position or title (--update-kernel) and args (--args or --remove-args) required.\n"
;
return
undef
;
}
return
undef
unless
&_check_config
();
my
@config
=
@bootconfig
;
my
@sections
=
&_info
();
if
(
$params
{
'update-kernel'
} !~ /^\d+$/ ) {
$params
{
'update-kernel'
} =
&_lookup
(
$params
{
'update-kernel'
} );
}
my
$kcount
=
$#sections
- 1;
if
(
$params
{
'update-kernel'
} !~ /^\d+$/
||
$params
{
'update-kernel'
} < 0
||
$params
{
'update-kernel'
} >
$kcount
)
{
warn
"ERROR: Enter a default between 0 and $kcount.\n"
;
return
undef
;
}
my
$index
= -1;
foreach
(
@config
) {
if
(
$_
=~ /^\s*(image|other)/i ) {
$index
++;
}
if
(
$index
==
$params
{
'update-kernel'
} ) {
if
(
$_
=~ /(^\s
*append
[\s\=]+)(.*)\n/i ) {
my
$append
= $1;
my
$args
= $2;
$args
=~ s/\"|\'//g;
$args
=~ s/\s
*$params
{
'remove-args'
}\=*\S*//ig
if
defined
$params
{
'remove-args'
};
$args
=
$args
.
" "
.
$params
{
'args'
}
if
defined
$params
{
'args'
};
if
(
$_
eq
"$append\"$args\"\n"
) {
warn
"WARNING: No change made to args.\n"
;
return
undef
;
}
else
{
$_
=
"$append\"$args\"\n"
;
}
next
;
}
}
}
@bootconfig
=
@config
;
}
sub
remove {
my
$position
=
shift
;
my
@newconfig
;
return
undef
unless
defined
$position
;
return
undef
unless
&_check_config
();
my
@config
=
@bootconfig
;
my
@sections
=
&_info
();
if
(
$position
=~ /^end$/i ) {
$position
=
$#sections
- 1;
}
elsif
(
$position
=~ /^start$/i ) {
$position
= 0;
}
print
(
"Removing kernel $position.\n"
)
if
&debug
() > 1;
if
(
$position
!~ /^\d+$/ ) {
my
$removed
= 0;
for
(
my
$index
=
$#sections
;
$index
> 0 ;
$index
-- ) {
if
(
defined
$sections
[
$index
]{title}
&&
$position
eq
$sections
[
$index
]{title} )
{
$removed
++
if
&remove
(
$index
- 1 );
}
}
if
( !
$removed
) {
warn
"ERROR: No kernel with specified title.\n"
;
return
undef
;
}
}
elsif
(
$position
=~ /^\d+$/ ) {
if
(
$position
< 0 ||
$position
>
$#sections
) {
warn
"ERROR: Enter a position between 0 and $#sections.\n"
;
return
undef
;
}
my
$index
= -1;
foreach
(
@config
) {
if
(
$_
=~ /^\s*(image|other|title)/i ) {
$index
++;
}
if
(
$index
!=
$position
||
$_
=~ /^
push
(
@newconfig
,
$_
);
}
}
@bootconfig
=
@newconfig
;
&set_default
(0)
if
$position
==
$sections
[0]{
'default'
};
print
"Removed kernel $position.\n"
;
return
1;
}
else
{
warn
"WARNING: problem removing entered position.\n"
;
return
undef
;
}
}
sub
print_info {
my
$info
=
shift
;
return
undef
unless
defined
$info
;
return
undef
unless
&_check_config
();
print
(
"Printing config info.\n"
)
if
&debug
() > 1;
my
@config
=
@bootconfig
;
my
@sections
=
&_info
();
my
(
$start
,
$end
);
if
(
$info
=~ /
default
/i ) {
$start
=
$end
=
&get_default
();
}
elsif
(
$info
=~ /all/i ) {
$start
= 0;
$end
=
$#sections
- 1;
}
elsif
(
$info
=~ /^\d+/ ) {
$start
=
$end
=
$info
;
}
else
{
warn
"ERROR: input should be: #, default, or all.\n"
;
return
undef
;
}
if
(
$start
< 0 ||
$end
>
$#sections
- 1 ) {
warn
"ERROR: No kernels with that index.\n"
;
return
undef
;
}
for
my
$index
(
$start
..
$end
) {
print
"\nindex\t: $index\n"
;
$index
++;
foreach
(
sort
keys
( %{
$sections
[
$index
] } ) ) {
print
"$_\t: $sections[$index]{$_}\n"
;
}
}
}
sub
install {
return
&install_lilo
()
if
(
$bootloader
eq
'lilo'
);
return
&install_grub
()
if
(
$bootloader
eq
'grub'
);
return
&install_elilo
()
if
(
$bootloader
eq
'elilo'
);
return
&install_yaboot
()
if
(
$bootloader
eq
'yaboot'
);
}
sub
debug {
if
(
@_
) {
$debug
=
shift
;
}
return
$debug
;
}
sub
_check_config {
print
(
"Verifying config.\n"
)
if
&debug
() > 3;
if
(
$#bootconfig
< 5 ) {
warn
"ERROR: you must read a valid config file first.\n"
;
return
undef
;
}
return
1;
}
sub
_lookup {
my
$title
=
shift
;
my
@sections
=
&_info
();
for
my
$index
( 1 ..
$#sections
) {
if
( (
defined
$sections
[
$index
]{title} )
&& (
$title
eq
$sections
[
$index
]{title} ) )
{
return
$index
- 1;
}
}
return
undef
;
}
my
$detected_bootloader
;
my
$detected_architecture
;
if
(
defined
$params
{
'bootloader-probe'
} ) {
$detected_bootloader
= detect_bootloader()
||
warn
"Could not detect bootloader\n"
;
print
"$detected_bootloader\n"
;
exit
0;
}
elsif
(
defined
$params
{
'arch-probe'
} ) {
$detected_architecture
= detect_architecture(
$params
{
'arch-probe'
} )
||
warn
"Could not detect architecture\n"
;
print
"$detected_architecture\n"
;
exit
0;
}
elsif
(
defined
$params
{bootloader} ) {
$detected_bootloader
=
$params
{bootloader};
}
else
{
$detected_bootloader
= detect_bootloader()
||
die
"Could not detect bootloader\n"
;
}
$bootloader
=
$detected_bootloader
;
my
%cfg_files
= (
grub
=>
'/boot/grub/menu.lst'
,
lilo
=>
'/etc/lilo.conf'
,
elilo
=>
'/etc/elilo.conf'
,
yaboot
=>
'/etc/yaboot.conf'
);
$params
{config_file} =
$cfg_files
{
$bootloader
}
unless
defined
$params
{config_file};
die
(
"Can't read config file.\n"
)
unless
( -r
$params
{config_file} );
&debug
(
$params
{
'debug'
} )
if
(
defined
$params
{
'debug'
} );
if
(
defined
$params
{
'add-kernel'
} ||
defined
$params
{
'xenhyper'
} ) {
&read
(
$params
{config_file} );
&add
(
%params
);
&write
(
$params
{config_file} );
&install
()
unless
$detected_bootloader
eq
'grub'
;
}
elsif
(
defined
$params
{
'remove-kernel'
} ) {
&read
(
$params
{config_file} );
&remove
(
$params
{
'remove-kernel'
} );
&write
(
$params
{config_file} );
&install
()
unless
$detected_bootloader
eq
'grub'
;
}
elsif
(
defined
$params
{
'update-kernel'
} ||
defined
$params
{
'update-xenhyper'
} ) {
$params
{
'update-kernel'
} =
$params
{
'update-xenhyper'
}
if
defined
$params
{
'update-xenhyper'
};
&read
(
$params
{config_file} );
&update
(
%params
);
&write
(
$params
{config_file} );
&install
()
unless
$detected_bootloader
eq
'grub'
;
}
elsif
(
defined
$params
{info} ) {
&read
(
$params
{config_file} );
&print_info
(
$params
{info} );
}
elsif
(
defined
$params
{
'set-default'
} ) {
&read
(
$params
{config_file} );
&set_default
(
$params
{
'set-default'
} );
&write
(
$params
{config_file} );
&install
()
unless
$detected_bootloader
eq
'grub'
;
}
elsif
(
defined
$params
{
'default'
} ) {
&read
(
$params
{config_file} );
print
get_default() .
"\n"
;
}
elsif
(
defined
$params
{
'boot-once'
} &&
defined
$params
{
'title'
} ) {
if
(
$detected_bootloader
eq
'lilo'
) {
&boot_once_lilo
(
$params
{title} );
}
elsif
(
$detected_bootloader
eq
'elilo'
) {
&boot_once_elilo
(
$params
{title} );
}
else
{
print
"$detected_bootloader does not have boot-once support.\n"
;
print
"Setting as default instead.\n"
;
&read
(
$params
{config_file} );
&set_default
(
$params
{
'title'
} );
&write
(
$params
{config_file} );
}
}
sub
usage {
print
"Usage:
boottool [--bootloader-probe] [--arch-probe]
[--add-kernel=<kernel_path>] [--title=<kernel_title>]
[--position=<
[--args=<kernel_args>] [--initrd=<initrd_path>]
[--make-
default
] [--force] [--boot-once] [--install]
[--bootloader=<grub|lilo|elilo|yaboot>] [--config-file=<config_path>]
[--remove-kernel=<
[--update-kernel=<
[--info=<all|
default
|
[--xen] [--xenhyper=<kernel_path>] [--xenhyper-args=<kernel_args>]
[--help] [--debug=<0..5>]
Examples:
boottool --info all
boottool -a /boot/vmlinuz -t
'test'
-p end
boottool --remove-kernel 3
boottool -u title1 -remove-args
'ro'
boottool -u title1 -args
'arg1=test'
--xen
boottool -xh /boot/xen.gz -a /boot/vmlinuz -t test --xen
boottool --set-
default
1
exit
1;
}