dell-recovery_bootloader
- 安装时调用 build-factory.sh(在postinst中),该脚本虽然在这里被调用,但该脚本属于dell-recovery_all。
#!/bin/sh -e
. /usr/share/debconf/confmodule
case "$1" in
configure)
/usr/share/dell/grub/build-factory.sh
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
exit 0
build-factory.sh
[ -n "$TARGET" ] || TARGET=/var/lib/dell-recovery
[ -n "$SOURCE_GRUBDIR" ] || SOURCE_GRUBDIR=/usr/share/dell/grub
[ -n "$TARGET_GRUBCFG" ] || TARGET_GRUBCFG=$TARGET/grub.cfg
echo "Creating factory grub.cfg"
OS=$(lsb_release -s -d)
sed "s,#OS#,$OS,; /#UUID#/d" \
$SOURCE_GRUBDIR/recovery_partition.cfg \
> $TARGET_GRUBCFG
在/usr/share/dell/grub 生成一个grub.cfg
dell-recovery_casper
.
├── DEBIAN
│ ├── control
│ └── md5sums
└── usr
└── share
├── doc
│ └── dell-recovery-casper
│ ├── changelog.gz
│ └── copyright
└── initramfs-tools
├── hooks
│ └── dell-bootstrap -> ../../dell/casper/hooks/dell-bootstrap
└── scripts
└── casper-bottom
└── 99dell_bootstrap -> ../../../dell/casper/scripts/99dell_bootstrap
目录结构,向initramfs-tools中添加2个脚本(这两个脚本都在dell-recovery_all中)
其中dell-bootstrap是在生成initramfs的过程中被调用;99dell_bootstrap是放在initramfs中(即放在initrd中),在时机-----casper-bootom执行。
99dell_bootstrap
PREREQ=""
DESCRIPTION="Running DELL bootstrap..."
prereqs ()
{
echo "$PREREQ"
}
case $1 in
# get pre-requisites
prereqs)
prereqs
exit 0
;;
esac
. /scripts/casper-functions
load_confmodule
log_begin_msg "$DESCRIPTION"
export DEBIAN_HAS_FRONTEND=
export DEBCONF_REDIR=
export DEBIAN_FRONTEND=noninteractive
# Early emergency installer fix
if [ -e /root/cdrom/scripts/emergency.sh ]; then
. /root/cdrom/scripts/emergency.sh
elif [ -e /root/isodevice/scripts/emergency.sh ]; then
. /root/isodevice/scripts/emergency.sh
fi
if [ -d /root/isodevice ]; then
if [ -f /root/isodevice/.disk/info.recovery -a ! -f /root/isodevice/.disk/info ]; then
mount -o remount,rw /root/isodevice
cp /root/isodevice/.disk/info.recovery /root/isodevice/.disk/info
mount -o remount,ro /root/isodevice
fi
elif [ -f /root/cdrom/.disk/info.recovery -a ! -f /root/cdrom/.disk/info ]; then
mount -o remount,rw /root/cdrom
cp /root/cdrom/.disk/info.recovery /root/cdrom/.disk/info
mount -o remount,ro /root/cdrom
fi
#Force ubiquity to run in automatic regardless if there are ubiquity options in /proc/cmdline (except single user mode)
if ! grep -q "single" /proc/cmdline 2>&1 >/dev/null; then
sed -i "s/ubiquity=\$/ubiquity=1/; s/\$automatic\ \$choose/--automatic/" /root/etc/init/ubiquity.conf
fi
#if they use a ubiquity icon it needs to run in automatic
if [ -f /root/etc/init.d/casper ]; then
sed -i "s/prompt=1$/prompt=/;" /root/etc/init.d/casper
fi
sed -i "s/Exec=ubiquity/Exec=ubiquity --automatic/" /root/usr/share/applications/ubiquity-gtkui.desktop 2>/dev/null || true
#Build custom pool (static and dynamic)
if [ ! -x /root/usr/share/dell/scripts/pool.sh ]; then
mkdir -p /root/usr/share/dell/scripts/
cp /scripts/pool.sh /root/usr/share/dell/scripts/
fi
chroot /root /usr/share/dell/scripts/pool.sh
#install if not installed, otherwise this will upgrade
chroot /root apt-get install dell-recovery -y --no-install-recommends
#only if we are in factory or bto-a
if chroot /root apt-cache show fist 2>/dev/null 1>/dev/null; then
chroot /root apt-get install fist -y
fi
###Set up all preseeds###
# First test for and load override / configurations preseeds
# - needs to be loaded first so that we know if we are dual boot
for seed in dell-recovery gfx wlan; do
if [ -e /root/cdrom/preseed/$seed.seed ]; then
casper-set-selections /root/cdrom/preseed/$seed.seed
fi
done
# Now load all the defaults included in all installs
casper-set-selections "/root/usr/share/dell/casper/seeds/ubuntu.seed"
# If we have a dual boot option, load the dual boot preseed
if db_get dell-recovery/dual_boot && [ "$RET" = true ]; then
casper-set-selections "/root/usr/share/dell/casper/seeds/dual.seed"
fi
# Lastly, reload the override / configurations preseeds so that it is allowed to override stuff from ubuntu.seed and dual.seed
for seed in dell-recovery gfx wlan; do
if [ -e /root/cdrom/preseed/$seed.seed ]; then
casper-set-selections /root/cdrom/preseed/$seed.seed
fi
done
# if no efibootmgr in livefs, force it. needed for stage1
if [ -d /sys/firmware/efi ] && [ ! -x /root/bin/efibootmgr ]; then
chroot /root apt-get install efibootmgr -y
fi
# disable snapd during installation to prevent OOM on small configurations
ln -s /dev/null /root/etc/systemd/system/snapd.service
# In case we're running a kernel not in the squashfs already
# we need to load modules into squashfs somehow
KERNELS=$(find /root/cdrom/kernel -maxdepth 1 -type d 2>/dev/null | sed "s,/root,,; /\/cdrom\/kernel\/$/d")
if [ -n "$KERNELS" ]; then
for KERNEL in $KERNELS; do
ln -s $KERNEL /root/lib/modules
done
fi
# Clear out debconf database backup files to save memory.
rm -f /root/var/cache/debconf/*.dat-old
# Later emergency installer fixes
if [ -d /root/cdrom/scripts/emergency-scripts ]; then
for script in /root/cdrom/scripts/emergency-scripts/[0-9]*; do
. $script
done
elif [ -d /root/isodevice/scripts/emergency-scripts ]; then
for script in /root/isodevice/scripts/emergency-scripts/[0-9]*; do
. $script
done
fi
log_end_msg
exit 0
dell_bootstrap
#!/bin/sh -e
# initramfs hook for dell-bootstrap
PREREQS=""
# Output pre-requisites
prereqs()
{
echo "$PREREQS"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
cp /usr/share/dell/scripts/pool.sh $DESTDIR/scripts
if [ ! -f $DESTDIR/scripts/casper-bottom/99dell_bootstrap ]; then
cp /usr/share/dell/casper/scripts/99dell_bootstrap $DESTDIR/scripts/casper-bottom
fi
#invoked from dell-recovery
if [ -n "$INJECT" ]; then
if ! grep 99dell_bootstrap $DESTDIR/scripts/casper-bottom/ORDER >/dev/null; then
cat >> $DESTDIR/scripts/casper-bottom/ORDER << EOF
/scripts/casper-bottom/99dell_bootstrap "\$@"
[ -e /conf/param.conf ] && . /conf/param.conf
EOF
fi
fi
主要作的事儿
- 强制修改ubiquity运行在 AUTOMATIC 模式下。(包括桌面快捷方式)
- 配置源(见pool.sh)
- 安装dell-recovery
- 使用seed文件,预置debconf的值
pool.sh
#!/bin/sh
#
# <pool.sh>
#
# Builds a pool from important stuff in /cdrom
# * Expects to be called as root w/ /cdrom referring to our stuff
#
# Copyright 2010 Dell Inc.
# Mario Limonciello <Mario_Limonciello@Dell.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
# vim:ts=8:sw=8:et:tw=0
[ -d /cdrom/debs ] || [ -d /isodevice/debs ] || [ -d /dell/debs ]
#Persistent mode has a tendency to break the dynamic apt cache
if grep -q persistent /proc/cmdline 2>/dev/null; then
rm -f /etc/apt/sources.list.d/dell.list
fi
#This allows things that aren't signed to be installed
if [ ! -f /etc/apt/apt.conf.d/00AllowUnauthenticated ]; then
cat > /etc/apt/apt.conf.d/00AllowUnauthenticated << EOF
APT::Get::AllowUnauthenticated "true";
Aptitude::CmdLine::Ignore-Trust-Violations "true";
Acquire::AllowInsecureRepositories "true";
EOF
fi
#Prevents apt-get from complaining about unmounting and mounting the hard disk
if [ ! -f /etc/apt/apt.conf.d/00NoMountCDROM ]; then
cat > /etc/apt/apt.conf.d/00NoMountCDROM << EOF
APT::CDROM::NoMount "true";
Acquire::cdrom
{
mount "/cdrom";
"/cdrom/"
{
Mount "true";
UMount "true";
};
AutoDetect "false";
};
EOF
fi
if [ ! -f /etc/apt/sources.list.d/dell.list ]; then
#extra sources need to be disabled for this
if find /etc/apt/sources.list.d/ -type f | grep sources.list.d; then
mkdir -p /etc/apt/sources.list.d.old
mv /etc/apt/sources.list.d/* /etc/apt/sources.list.d.old
fi
#Produce a dynamic list
for dir in /cdrom/debs /isodevice/debs /dell/debs;
do
if [ -d "$dir" ]; then
cd $dir
apt-ftparchive packages ../../$dir | sed "s/^Filename:\ ..\//Filename:\ .\//" >> /Packages
fi
done
if [ -f /Packages ]; then
echo "deb file:/ /" > /etc/apt/sources.list.d/dell.list
fi
#add the static list to our file
apt-cdrom -m add
if grep "^deb cdrom" /etc/apt/sources.list >> /etc/apt/sources.list.d/dell.list; then
sed -i "/^deb\ cdrom/d" /etc/apt/sources.list
fi
#fill up the cache
mv /etc/apt/sources.list /etc/apt/sources.list.ubuntu
touch /etc/apt/sources.list
apt-get update
fi
if [ "$1" = "cleanup" ]; then
#cleanup
#if /etc/apt/sources.list has contained the regional mirror site, it is better to use it.
if grep -v "^#" /etc/apt/sources.list | grep archive.ubuntu.com >/dev/null 2>&1; then
rm -f /etc/apt/sources.list.ubuntu
# Ensure Canonical's 'partner' repository enabled.
sed -i 's/# deb \(.*\) partner$/deb \1 partner/g' /etc/apt/sources.list
else
mv /etc/apt/sources.list.ubuntu /etc/apt/sources.list
fi
rm -f /Packages /etc/apt/apt.conf.d/00AllowUnauthenticated /etc/apt/apt.conf.d/00NoMountCDROM
rm -f /etc/apt/sources.list.d/dell.list
if [ -d /etc/apt/sources.list.d.old ]; then
mv /etc/apt/sources.list.d.old/* /etc/apt/sources.list.d
rm -rf /etc/apt/sources.list.d.old
fi
fi
live中的grub.cfg
来自:
shutil.copy('/usr/share/dell/grub/theme/grub.cfg',
os.path.join(tmpdir, 'boot', 'grub', 'grub.cfg'))
这个处理是在recovery_backend中。
其中 /usr/share/dell/grub/theme/grub.cfg内容:
#########################################################
# #
# Dell Grub2 configuration file for ISO Images #
# By: Mario Limonciello <Mario_Limonciello@Dell.com> #
# #
#########################################################
# First check for additional options on ISO image
if [ -s /factory/common.cfg ]; then
source /factory/common.cfg
fi
#Post RTS deliverables
if [ -s /factory/post-rts-gfx.cfg ]; then
source /factory/post-rts-gfx.cfg
fi
if [ -s /factory/post-rts-wlan.cfg ]; then
source /factory/post-rts-wlan.cfg
fi
# If missing, load a nice basic default set
if [ -z "${options}" ]; then
set options="boot=casper automatic-ubiquity noprompt quiet splash nomodeset nopersistent --"
fi
# Setup theme
set timeout=2
set gfxmode=auto
insmod gfxterm
terminal_output gfxterm
loadfont /boot/grub/dejavu-sans-12.pf2
loadfont /boot/grub/dejavu-sans-bold-14.pf2
insmod gfxmenu
insmod png
set theme=/boot/grub/dell/theme.txt
# Search for the RP (which contains grubenv in /factory)
search --file --set=new_root /factory/grubenv
if [ -s ($new_root)/factory/grubenv ]; then
set have_grubenv=true
load_env -f ($new_root)/factory/grubenv
if [ "x${install_in_progress}" = "x1" ]; then
set root=$new_root
configfile ($new_root)/factory/grub.cfg
else
set timeout=-1
menuentry "Install Complete, remove media and reboot." {
chainloader +1
}
fi
fi
#allow OS to choose kernel extension if it wants
kernel=/casper/vmlinuz
if [ ! -f $kernel ]; then
kernel=/casper/vmlinuz.efi
fi
#Default behavior
menuentry "Dell Recovery" {
set gfxpayload=keep
linux $kernel $options
initrd /casper/initrd
}
live中factory中的grub.cfg来自
#Check for a grub.cfg - replace as necessary
files = {'recovery_partition.cfg': 'grub.cfg',
}
for item in files:
full_path = os.path.join('/mnt', 'factory', files[item])
if os.path.exists(full_path):
with misc.raised_privileges():
shutil.move(full_path, full_path + '.old')
with misc.raised_privileges():
magic.process_conf_file('/usr/share/dell/grub/' + item, \
full_path, uuid, EFI_RP_PARTITION)
该处理在dell-recovery中(ubiquity的插件)
将 /usr/share/dell/grub/recovery_partition.cfg 处理过后(替换UUID等)放入 /mnt/factory/grub.cfg中
##set install_in_progress flag
with misc.raised_privileges():
if not os.path.exists('/mnt/factory/grub.cfg'):
build = misc.execute_root('/usr/share/dell/grub/build-factory.sh')
if build is False:
raise RuntimeError("Error building grub cfg.")
with misc.raised_privileges():
magic.white_tree("copy", re.compile('.'), '/var/lib/dell-recovery', '/mnt/factory')
magic.fetch_output(['grub-editenv', '/mnt/factory/grubenv', 'set', 'install_in_progress=1'])
这里感觉有点重复 不知道什么情况会导致 /mnt/factory/grub.cfg不存在。
magic.fetch_output(['grub-editenv', '/mnt/factory/grubenv', 'set', 'install_in_progress=1']这个标记在grub阶段很重要!!!!
#########################################################
# #
# Dell Grub2 configuration file for recovery partitions #
# By: Mario Limonciello <Mario_Limonciello@Dell.com> #
# #
#########################################################
#
# Try to load the grub environment. We may have set a failure bit here.
# If the failure bit is set, then we don't default to automatic install
#
if [ -s /factory/grubenv ]; then
set have_grubenv=true
load_env -f /factory/grubenv
fi
if [ "${recordfail}" = 1 ]; then
set timeout=-1
set default=0
else
set timeout=0
set default=7
fi
#
# Load other misc defaults
#
#First check our current directory for additional options
if [ -s /factory/common.cfg ]; then
source /factory/common.cfg
fi
#Post RTS deliverables
if [ -s /factory/post-rts-gfx.cfg ]; then
source /factory/post-rts-gfx.cfg
fi
if [ -s /factory/post-rts-wlan.cfg ]; then
source /factory/post-rts-wlan.cfg
fi
#Now set the root partition that has our OS installer
search --no-floppy --hint '(hd0,#PARTITION#)' --set --fs-uuid #UUID#
#If we still don't have options, they are on the the RP too, look there
#If missing, load a nice basic default set
if [ -z "${options}" ]; then
if [ -s /factory/common.cfg ]; then
source /factory/common.cfg
else
set options="boot=casper automatic-ubiquity noprompt quiet splash nomodeset nopersistent --"
fi
#Post RTS deliverables
if [ -s /factory/post-rts-gfx.cfg ]; then
source /factory/post-rts-gfx.cfg
fi
if [ -s /factory/post-rts-wlan.cfg ]; then
source /factory/post-rts-wlan.cfg
fi
fi
set uuid_options="uuid=#UUID#"
#Support starting from a loopback mount (Only support ubuntu.iso for filename)
if [ -f /ubuntu.iso ]; then
loopback loop /ubuntu.iso
set root=(loop)
set loop_options="iso-scan/filename=/ubuntu.iso"
fi
set menu_color_normal=white/red
set menu_color_highlight=red/white
#
# Show the menu if we press shift
#
if [ "x${timeout}" != "x-1" ]; then
if keystatus; then
if keystatus --shift; then
set timeout=-1
else
set timeout=0
fi
else
if sleep --interruptible 3 ; then
set timeout=0
fi
fi
fi
#Set up for EFI if need be
if loadfont /boot/grub/font.pf2 ; then
set gfxmode=auto
insmod efi_gop
insmod efi_uga
insmod gfxterm
terminal_output gfxterm
fi
kernel=/casper/vmlinuz
if [ ! -f $kernel ]; then
kernel=/casper/vmlinuz.efi
fi
#We currently assume all machines can do this
#There is a blacklist system in ubuntu though
#that can be implemented if need be.
set gfxpayload=keep
#
# Debugging information and options
#
menuentry "If you are seeing this menu, your installation has failed." {
chainloader +1
}
#
# Add collecting logs function for factory to provide more failed info to analysis issue
#
menuentry "To collect logs insert a USB recovery stick and select one of these options:" {
chainloader +1
}
menuentry " Collect OS installation logs" {
search --file --set=new_root /efi/boot/grubx64.efi
set root=$new_root
linux $kernel $options
initrd /casper/initrd
}
menuentry " Collect OS installation logs (command line mode)" {
search --file --set=new_root /efi/boot/grubx64.efi
set root=$new_root
linux $kernel boot=casper automatic-ubiquity noprompt quiet nomodeset nopersistent init=/bin/bash
initrd /casper/initrd
}
menuentry "For interactive debugging select the following option:" {
chainloader +1
}
menuentry " Single User Mode" {
linux $kernel boot=casper noprompt single nopersistent $uuid_options $loop_options --
initrd /casper/initrd
}
#
# Default option
#
menuentry "To try install again select this option:" {
chainloader +1
}
menuentry " Automated Installation of #OS# (Default)" {
set recordfail=1
if [ -n "${have_grubenv}" ]; then save_env -f /factory/grubenv recordfail; fi
linux $kernel $uuid_options $options $loop_options
initrd /casper/initrd
}
关于EFI
#Install grub
self.status("Installing GRUB", 88)
##If we don't have grub binaries, build them
grub_files = ['bootx64.efi', 'grubx64.efi']
##Mount ESP
mount = misc.execute_root('mount', self.device + esp_part, '/mnt/efi')
if mount is False:
raise RuntimeError("Error mounting %s%s" % (self.device, esp_part))
direct_path = '/mnt/efi' + '/efi/ubuntu'
with misc.raised_privileges():
os.makedirs(direct_path)
#copy boot loader files
for root, dirs, files in os.walk('/cdrom', topdown=False):
for bootloader in grub_files:
for f in files:
if bootloader in f.lower():
shutil.copy(os.path.join(root,f), direct_path)
#find old entries
bootmgr_output = magic.fetch_output(['efibootmgr', '-v']).split('\n')
#delete old entries
for line in bootmgr_output:
bootnum = ''
if line.startswith('Boot') and 'ubuntu' in line.lower():
bootnum = line.split('Boot')[1].replace('*', '').split()[0]
if bootnum:
bootmgr = misc.execute_root('efibootmgr', '-v', '-b', bootnum, '-B')
if bootmgr is False:
raise RuntimeError("Error removing old EFI boot manager entries")
target = 'shimx64.efi'
with misc.raised_privileges():
os.rename(os.path.join(direct_path, 'bootx64.efi'),
os.path.join(direct_path, target))
add = misc.execute_root('efibootmgr', '-v', '-c', '-d', self.device, '-p', EFI_ESP_PARTITION, '-l', '\\EFI\\ubuntu\\%s' % target, '-L', 'ubuntu')
if add is False:
raise RuntimeError("Error adding efi entry to %s%s" % (self.device, esp_part))