heads/initrd/bin/kexec-parse-boot

260 lines
5.2 KiB
Plaintext
Raw Normal View History

#!/bin/bash
set -e -o pipefail
. /etc/functions
TRACE "Under /bin/kexec-parse-boot"
bootdir="$1"
file="$2"
if [ -z "$bootdir" -o -z "$file" ]; then
die "Usage: $0 /boot /boot/grub/grub.cfg"
fi
reset_entry() {
name=""
kexectype="elf"
kernel=""
initrd=""
modules=""
append=""
}
filedir=`dirname $file`
DEBUG "filedir= $filedir"
bootdir="${bootdir%%/}"
DEBUG "bootdir= $bootdir"
bootlen="${#bootdir}"
DEBUG "bootlen= $bootlen"
appenddir="${filedir:$bootlen}"
DEBUG "appenddir= $appenddir"
fix_path() {
path="$@"
if [ "${path:0:1}" != "/" ]; then
DEBUG "fix_path: path was $@"
path="$appenddir/$path"
DEBUG "fix_path: path is now $path"
fi
}
# GRUB kernel lines (linux/multiboot) can include a command line. Check whether
# the file path exists in $bootdir.
check_path() {
local checkpath firstval
checkpath="$1"
firstval="$(echo "$checkpath" | cut -d\ -f1)"
if ! [ -r "$bootdir$firstval" ]; then
DEBUG "$bootdir$firstval doesn't exist"
return 1;
fi
return 0
}
echo_entry() {
if [ -z "$kernel" ]; then return; fi
fix_path $kernel
# The kernel must exist - if it doesn't, ignore this entry, it
# wouldn't work anyway. This could happen if there was a
# GRUB variable in the kernel path, etc.
if ! check_path "$path"; then return; fi
entry="$name|$kexectype|kernel $path"
case "$kexectype" in
elf)
if [ -n "$initrd" ]; then
for init in $(echo $initrd | tr ',' ' '); do
fix_path $init
# The initrd must also exist
if ! check_path "$path"; then return; fi
entry="$entry|initrd $path"
done
fi
if [ -n "$append" ]; then
entry="$entry|append $append"
fi
;;
multiboot|xen)
entry="$entry$modules"
;;
*)
return
;;
esac
# Double-expand here in case there are variables in the kernel
# parameters - some configs do this and can boot with empty
# expansions (Debian Live ISOs use this for loopback boots)
echo $(eval "echo \"$entry\"")
}
search_entry() {
case $line in
menuentry* | MENUENTRY* )
state="grub"
reset_entry
name=`echo $line | tr "'" "\"" | cut -d\" -f 2`
;;
label* | LABEL* )
state="syslinux"
reset_entry
name=`echo $line | cut -c6- `
esac
}
grub_entry() {
if [ "$line" = "}" ]; then
echo_entry
state="search"
return
fi
# add info to menuentry
trimcmd=`echo $line | tr '\t ' ' ' | tr -s ' '`
cmd=`echo $trimcmd | cut -d\ -f1`
val=`echo $trimcmd | cut -d\ -f2-`
case $cmd in
multiboot*)
# TODO: differentiate between Xen and other multiboot kernels
kexectype="xen"
kernel="$val"
DEBUG " grub_entry multiboot kernel= $kernel"
;;
module*)
2017-04-30 01:50:10 +00:00
case $val in
--nounzip*) val=`echo $val | cut -d\ -f2-` ;;
esac
fix_path $val
modules="$modules|module $path"
DEBUG " grub_entry linux modules= $modules"
;;
linux*)
# Some configs have a device specification in the kernel
# or initrd path. Assume this would be /boot and remove
# it. Keep the '/' following the device, since this
# path is relative to the device root, not the config
# location.
DEBUG " grub_entry : linux trimcmd prior of kernel/append parsing: $trimcmd"
kernel=`echo $trimcmd | sed "s/([^)]*)//g" | cut -d\ -f2`
append=`echo $trimcmd | cut -d\ -f3-`
;;
initrd*)
# Trim off device specification as above
initrd="$(echo "$val" | sed "s/([^)]*)//g")"
DEBUG " grub_entry: linux initrd= $initrd"
;;
esac
}
syslinux_end() {
# finish menuentry
# attempt to parse out of append if missing initrd
if [ -z "$initrd" ]; then
newappend=""
for param in $append; do
case $param in
initrd=*)
initrd=`echo $param | cut -d\= -f2`
;;
*) newappend="$newappend $param" ;;
esac
done
append="${newappend##' '}"
fi
appenddir="$(echo $appenddir | cut -d\/ -f -2)"
echo_entry
state="search"
}
syslinux_multiboot_append() {
splitval=`echo "${val// --- /|}" | tr '|' '\n'`
while read line
do
if [ -z "$kernel" ]; then
kernel="$line"
else
fix_path $line
modules="$modules|module $path"
fi
done << EOF
$splitval
EOF
}
syslinux_entry() {
2017-04-30 01:50:10 +00:00
case $line in
"")
syslinux_end
return
;;
label* | LABEL* )
syslinux_end
search_entry
return
;;
esac
# add info to menuentry
trimcmd=`echo $line | tr '\t ' ' ' | tr -s ' '`
cmd=`echo $trimcmd | cut -d\ -f1`
val=`echo $trimcmd | cut -d\ -f2-`
case $trimcmd in
menu* | MENU* )
cmd2=`echo $trimcmd | cut -d \ -f2`
if [ "$cmd2" = "label" -o "$cmd2" = "LABEL" ]; then
name=`echo $trimcmd | cut -c11- | tr -d '^'`
fi
;;
linux* | LINUX* | kernel* | KERNEL* )
case $val in
# TODO: differentiate between Xen and other multiboot kernels
*mboot.c32) kexectype="xen" ;;
*.c32)
# skip this entry
state="search"
;;
*)
kernel="$val"
DEBUG "kernel= $kernel"
esac
;;
initrd* | INITRD* )
initrd="$val"
DEBUG "initrd= $initrd"
;;
append* | APPEND* )
if [ "$kexectype" = "multiboot" -o "$kexectype" = "xen" ]; then
syslinux_multiboot_append
else
append="$val"
DEBUG "append= $append"
fi
;;
esac
}
state="search"
while read line
do
case $state in
search)
search_entry
;;
grub)
grub_entry
;;
syslinux)
syslinux_entry
;;
esac
done < "$file"
# handle EOF case
if [ "$state" = "syslinux" ]; then
syslinux_end
fi