summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/freebsd-update.conf11
-rw-r--r--share/man/man5/freebsd-update.conf.552
-rw-r--r--usr.sbin/freebsd-update/freebsd-update.sh162
3 files changed, 222 insertions, 3 deletions
diff --git a/etc/freebsd-update.conf b/etc/freebsd-update.conf
index af53be4..4410903 100644
--- a/etc/freebsd-update.conf
+++ b/etc/freebsd-update.conf
@@ -63,3 +63,14 @@ MergeChanges /etc/ /var/named/etc/ /boot/device.hints
# which *might* be installed of which FreeBSD Update should figure out
# which actually are installed and upgrade those (StrictComponents no)?
# StrictComponents no
+
+# When installing a new kernel perform a backup of the old one first
+# so it is possible to boot the old kernel in case of problems.
+# BackupKernel yes
+
+# If BackupKernel is enabled, the backup kernel is saved to this
+# directory.
+# BackupKernelDir /boot/kernel.old
+
+# When backing up a kernel also back up debug symbol files?
+# BackupKernelSymbolFiles no
diff --git a/share/man/man5/freebsd-update.conf.5 b/share/man/man5/freebsd-update.conf.5
index 29775fd..d372102 100644
--- a/share/man/man5/freebsd-update.conf.5
+++ b/share/man/man5/freebsd-update.conf.5
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 30, 2006
+.Dd August 19, 2009
.Dt FREEBSD-UPDATE.CONF 5
.Os FreeBSD
.Sh NAME
@@ -48,7 +48,7 @@ error.
.Pp
The possible options and their meanings are as follows:
.Pp
-.Bl -tag -width "KeepModifiedMetadata"
+.Bl -tag -width ".Cm BackupKernelSymbolFiles"
.It Cm KeyPrint
The single parameter following this keyword is the SHA256 hash
of the RSA key which will be trusted to sign updates.
@@ -171,6 +171,54 @@ command is used ("yes"), or merely as a list of components
which might be installed, of which
.Cm freebsd-update
should identify which in fact are present ("no").
+.It Cm BackupKernel
+The single parameter following this keyword must be
+.Dq yes
+or
+.Dq no
+and specifies whether
+.Cm freebsd-update
+will create a backup of the old kernel before installing a new kernel.
+This backup kernel can be used to recover a system where the newly
+installed kernel somehow did not work.
+Note that the backup kernel is not reverted to its original state by
+the
+.Cm freebsd-update
+rollback command.
+.It Cm BackupKernelDir
+This keyword sets the directory which is used to store a backup
+kernel, if the BackupKernel feature is enabled.
+If the directory already exist, and it was not created by
+.Cm freebsd-update ,
+the directory is skipped.
+In the case of the primary directory name not being usable, a number
+starting with
+.Sq 1
+is appended to the directory name.
+Like with the primary directory name, the constructed directory name is
+only used if the path name does not exist, or if the directory was
+previously created by
+.Cm freebsd-update .
+If the constructed directory still exist the appended number is
+incremented with 1 and the directory search process restarted.
+Should the number increment go above 9,
+.Cm freebsd-update
+will abort.
+.It Cm BackupKernelSymbolFiles
+The single parameter following this keyword must be
+.Dq yes
+or
+.Dq no
+and specifies whether
+.Cm freebsd-update
+will also backup kernel symbol files, if they exist.
+The kernel symbol files takes up a lot of disk space and are not
+needed for recovery purposes.
+If the symbol files are needed, after recovering a system using the
+backup kernel, the
+.Cm freebsd-update
+rollback command will recreate the symbol files along with the old
+kernel.
.El
.Sh FILES
.Bl -tag -width "/etc/freebsd-update.conf"
diff --git a/usr.sbin/freebsd-update/freebsd-update.sh b/usr.sbin/freebsd-update/freebsd-update.sh
index 331ef10..2eacca8 100644
--- a/usr.sbin/freebsd-update/freebsd-update.sh
+++ b/usr.sbin/freebsd-update/freebsd-update.sh
@@ -88,7 +88,7 @@ EOF
CONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE
KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED
BASEDIR VERBOSELEVEL TARGETRELEASE STRICTCOMPONENTS MERGECHANGES
- IDSIGNOREPATHS"
+ IDSIGNOREPATHS BACKUPKERNEL BACKUPKERNELDIR BACKUPKERNELSYMBOLFILES"
# Set all the configuration options to "".
nullconfig () {
@@ -308,6 +308,70 @@ config_VerboseLevel () {
fi
}
+config_BackupKernel () {
+ if [ -z ${BACKUPKERNEL} ]; then
+ case $1 in
+ [Yy][Ee][Ss])
+ BACKUPKERNEL=yes
+ ;;
+ [Nn][Oo])
+ BACKUPKERNEL=no
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+ else
+ return 1
+ fi
+}
+
+config_BackupKernelDir () {
+ if [ -z ${BACKUPKERNELDIR} ]; then
+ if [ -z "$1" ]; then
+ echo "BackupKernelDir set to empty dir"
+ return 1
+ fi
+
+ # We check for some paths which would be extremely odd
+ # to use, but which could cause a lot of problems if
+ # used.
+ case $1 in
+ /|/bin|/boot|/etc|/lib|/libexec|/sbin|/usr|/var)
+ echo "BackupKernelDir set to invalid path $1"
+ return 1
+ ;;
+ /*)
+ BACKUPKERNELDIR=$1
+ ;;
+ *)
+ echo "BackupKernelDir ($1) is not an absolute path"
+ return 1
+ ;;
+ esac
+ else
+ return 1
+ fi
+}
+
+config_BackupKernelSymbolFiles () {
+ if [ -z ${BACKUPKERNELSYMBOLFILES} ]; then
+ case $1 in
+ [Yy][Ee][Ss])
+ BACKUPKERNELSYMBOLFILES=yes
+ ;;
+ [Nn][Oo])
+ BACKUPKERNELSYMBOLFILES=no
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+ else
+ return 1
+ fi
+}
+
# Handle one line of configuration
configline () {
if [ $# -eq 0 ]; then
@@ -461,6 +525,9 @@ default_params () {
config_BaseDir /
config_VerboseLevel stats
config_StrictComponents no
+ config_BackupKernel yes
+ config_BackupKernelDir /boot/kernel.old
+ config_BackupKernelSymbolFiles no
# Merge these defaults into the earlier-configured settings
mergeconfig
@@ -665,6 +732,14 @@ install_check_params () {
echo "Re-run '$0 fetch'."
exit 1
fi
+
+ # Figure out what directory contains the running kernel
+ BOOTFILE=`sysctl -n kern.bootfile`
+ KERNELDIR=${BOOTFILE%/kernel}
+ if ! [ -d ${KERNELDIR} ]; then
+ echo "Cannot identify running kernel"
+ exit 1
+ fi
}
# Perform sanity checks and set some final parameters in
@@ -2494,6 +2569,88 @@ install_unschg () {
rm filelist
}
+# Decide which directory name to use for kernel backups.
+backup_kernel_finddir () {
+ CNT=0
+ while true ; do
+ # Pathname does not exist, so it is OK use that name
+ # for backup directory.
+ if [ ! -e $BACKUPKERNELDIR ]; then
+ return 0
+ fi
+
+ # If directory do exist, we only use if it has our
+ # marker file.
+ if [ -d $BACKUPKERNELDIR -a \
+ -e $BACKUPKERNELDIR/.freebsd-update ]; then
+ return 0
+ fi
+
+ # We could not use current directory name, so add counter to
+ # the end and try again.
+ CNT=$((CNT + 1))
+ if [ $CNT -gt 9 ]; then
+ echo "Could not find valid backup dir ($BACKUPKERNELDIR)"
+ exit 1
+ fi
+ BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`"
+ BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}"
+ done
+}
+
+# Backup the current kernel using hardlinks, if not disabled by user.
+# Since we delete all files in the directory used for previous backups
+# we create a marker file called ".freebsd-update" in the directory so
+# we can determine on the next run that the directory was created by
+# freebsd-update and we then do not accidentally remove user files in
+# the unlikely case that the user has created a directory with a
+# conflicting name.
+backup_kernel () {
+ # Only make kernel backup is so configured.
+ if [ $BACKUPKERNEL != yes ]; then
+ return 0
+ fi
+
+ # Decide which directory name to use for kernel backups.
+ backup_kernel_finddir
+
+ # Remove old kernel backup files. If $BACKUPKERNELDIR was
+ # "not ours", backup_kernel_finddir would have exited, so
+ # deleting the directory content is as safe as we can make it.
+ if [ -d $BACKUPKERNELDIR ]; then
+ rm -f $BACKUPKERNELDIR/*
+ fi
+
+ # Create directory for backup if it doesn't exist.
+ mkdir -p $BACKUPKERNELDIR
+
+ # Mark the directory as having been created by freebsd-update.
+ touch $BACKUPKERNELDIR/.freebsd-update
+ if [ $? -ne 0 ]; then
+ echo "Could not create kernel backup directory"
+ exit 1
+ fi
+
+ # Disable pathname expansion to be sure *.symbols is not
+ # expanded.
+ set -f
+
+ # Use find to ignore symbol files, unless disabled by user.
+ if [ $BACKUPKERNELSYMBOLFILES = yes ]; then
+ FINDFILTER=""
+ else
+ FINDFILTER=-"a ! -name *.symbols"
+ fi
+
+ # Backup all the kernel files using hardlinks.
+ find $KERNELDIR -type f $FINDFILTER | \
+ sed -Ee "s,($KERNELDIR)/?(.*),\1/\2 ${BACKUPKERNELDIR}/\2," | \
+ xargs -n 2 cp -pl
+
+ # Re-enable patchname expansion.
+ set +f
+}
+
# Install new files
install_from_index () {
# First pass: Do everything apart from setting file flags. We
@@ -2575,6 +2732,9 @@ install_files () {
grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
+ # Backup current kernel before installing a new one
+ backup_kernel || return 1
+
# Install new files
install_from_index INDEX-NEW || return 1
OpenPOWER on IntegriCloud