Support system upgrades and configuration in GRUB.

Move /etc/default/grub to /etc/grub as it's owned by the sysadmin.

Move /etc/grub.d to /etc/default/grub.d as it's owned by the system.

Support /etc/grub's GRUB_CMDLINE_SORTIX in 10_sortix.

Remove the old /etc/grub.d/10_sortix.cache with a compatibility hook as it
has moved to /etc/default/grub.d/10_sortix.cache.
This commit is contained in:
Jonas 'Sortie' Termansen 2023-08-07 21:31:59 +02:00
parent c4b878beb7
commit 938f2390dd
18 changed files with 609 additions and 223 deletions

View File

@ -1,2 +1,2 @@
chmod +x -- '10_sortix'
chmod +x -- 'update-grub'
chmod +x -- 'util/grub.d/10_sortix.in'

View File

@ -1,77 +1,58 @@
diff -Paur --no-dereference -- grub.upstream/10_sortix grub/10_sortix
--- grub.upstream/10_sortix
+++ grub/10_sortix
@@ -0,0 +1,70 @@
+#!/bin/sh -e
+! [ -e /etc/sortix-release ] && exit 0
+. /etc/sortix-release
+find_mountpoint() {(
+ FILE="$1"
+ DEVICE=$(grub-probe -t device -- "$FILE")
+ while [ "$FILE" != "/" ]; do
+ PARENT="$(dirname -- "$FILE")"
+ if [ x"$(grub-probe -t device -- "$PARENT")" != x"$DEVICE" ]; then
+ echo "$FILE"
+ exit 0
+ fi
+ FILE="$PARENT"
+ done
+ echo "$FILE"
+ exit 0
+)}
+mountpoint_relative() {(
+ REL=""
+ FILE="$1"
+ DEVICE=$(grub-probe -t device -- "$FILE")
+ while [ "$FILE" != "/" ]; do
+ PARENT="$(dirname -- "$FILE")"
+ if [ x"$(grub-probe -t device -- "$PARENT")" != x"$DEVICE" ]; then
+ echo "$REL"
+ exit 0
+ fi
+ REL="/$(basename -- "$FILE")$REL"
+ FILE="$PARENT"
+ done
+ echo "$REL"
+ exit 0
+)}
+BOOT_MNT=$(find_mountpoint /boot)
+BOOT_REL=$(mountpoint_relative /boot)
+DEVICE=$(grub-probe -t device -- "$BOOT_MNT")
+FS_UUID=$(grub-probe -t fs_uuid -- "$BOOT_MNT")
+HINTS_STRING=$(grub-probe -t hints_string -- "$BOOT_MNT")
+PARTMAP=$(grub-probe -t partmap -- "$BOOT_MNT")
+FS=$(grub-probe -t fs -- "$BOOT_MNT")
+echo "Found $PRETTY_NAME on $DEVICE" >&2
+cat > "$0.cache" << EOF
+menuentry "$PRETTY_NAME (on $DEVICE)" --unrestricted {
+ insmod part_$PARTMAP
+ insmod $FS
+ search --no-floppy --fs-uuid --set=root $HINTS_STRING $FS_UUID
+ if [ -e $BOOT_REL/sortix.bin.xz ]; then
+ insmod xzio
+ multiboot $BOOT_REL/sortix.bin.xz
+ elif [ -e $BOOT_REL/sortix.bin.gz ]; then
+ insmod gzio
+ multiboot $BOOT_REL/sortix.bin.gz
+ else
+ multiboot $BOOT_REL/sortix.bin
+ fi
+ if [ -e $BOOT_REL/random.seed ]; then
+ module $BOOT_REL/random.seed --random-seed
+ fi
+ if [ -e $BOOT_REL/sortix.initrd.xz ]; then
+ insmod xzio
+ module $BOOT_REL/sortix.initrd.xz
+ elif [ -e $BOOT_REL/sortix.initrd.gz ]; then
+ insmod gzio
+ module $BOOT_REL/sortix.initrd.gz
+ else
+ module $BOOT_REL/sortix.initrd
+ fi
+}
+EOF
+cat "$0.cache"
diff -Paur --no-dereference -- grub.upstream/Makefile.in grub/Makefile.in
--- grub.upstream/Makefile.in
+++ grub/Makefile.in
@@ -1212,6 +1212,7 @@
util/grub.d/10_kfreebsd.in util/grub.d/10_illumos.in \
util/grub.d/10_netbsd.in util/grub.d/10_linux.in \
util/grub.d/10_xnu.in util/grub.d/20_linux_xen.in \
+ util/grub.d/10_sortix.in \
util/grub.d/30_os-prober.in util/grub.d/40_custom.in \
util/grub.d/41_custom.in util/grub-mkconfig.in \
util/grub-set-default.in util/grub-reboot.in \
@@ -2372,7 +2373,7 @@
CCASFLAGS_LIBRARY =
# Other variables
-grubconfdir = $(sysconfdir)/grub.d
+grubconfdir = $(sysconfdir)/default/grub.d
platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
starfielddir = $(pkgdatadir)/themes/starfield
CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion
@@ -2440,6 +2441,7 @@
grubconf_SCRIPTS = 00_header $(am__append_57) $(am__append_61) \
$(am__append_65) $(am__append_69) $(am__append_73) \
$(am__append_77) $(am__append_81) $(am__append_85) \
+ 10_sortix \
30_os-prober 40_custom 41_custom
noinst_LIBRARIES = libgrubkern.a libgrubmods.a libgrubgcry.a
dist_noinst_DATA = grub-core/kern/disk_common.c \
@@ -2460,6 +2462,7 @@
util/grub.d/00_header.in $(am__append_60) $(am__append_64) \
$(am__append_68) $(am__append_72) $(am__append_76) \
$(am__append_80) $(am__append_84) $(am__append_88) \
+ util/grub.d/10_sortix.in \
util/grub.d/30_os-prober.in util/grub.d/40_custom.in \
util/grub.d/41_custom.in util/grub-mkconfig.in \
util/grub-set-default.in util/grub-reboot.in \
@@ -2640,6 +2643,7 @@
$(am__append_62) $(am__append_66) $(am__append_70) \
$(am__append_74) $(am__append_78) $(am__append_82) \
$(am__append_86) 30_os-prober 40_custom 41_custom \
+ 10_sortix \
$(am__append_89) grub-mkconfig $(am__append_90) \
grub-set-default $(am__append_91) grub-reboot \
grub-mkconfig_lib $(am__append_92) grub-kbdcomp grub-shell \
@@ -12086,6 +12090,10 @@
@COND_HOST_XNU_TRUE@ (for x in util/grub.d/10_xnu.in ; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
@COND_HOST_XNU_TRUE@ chmod a+x 10_xnu
+10_sortix: $(top_builddir)/config.status util/grub.d/10_sortix.in
+ (for x in util/grub.d/10_sortix.in ; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
+ chmod a+x 10_sortix
+
@COND_HOST_LINUX_TRUE@20_linux_xen: $(top_builddir)/config.status util/grub.d/20_linux_xen.in
@COND_HOST_LINUX_TRUE@ (for x in util/grub.d/20_linux_xen.in ; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:-
@COND_HOST_LINUX_TRUE@ chmod a+x 20_linux_xen
diff -Paur --no-dereference -- grub.upstream/build-aux/config.sub grub/build-aux/config.sub
--- grub.upstream/build-aux/config.sub
+++ grub/build-aux/config.sub
@ -226,6 +207,18 @@ diff -Paur --no-dereference -- grub.upstream/configure grub/configure
FREETYPE=$ac_cv_prog_FREETYPE
if test -n "$FREETYPE"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE" >&5
diff -Paur --no-dereference -- grub.upstream/grub-core/Makefile.in grub/grub-core/Makefile.in
--- grub.upstream/grub-core/Makefile.in
+++ grub/grub-core/Makefile.in
@@ -13658,7 +13658,7 @@
CCASFLAGS_LIBRARY = $(CCASFLAGS_PLATFORM)
# Other variables
-grubconfdir = $(sysconfdir)/grub.d
+grubconfdir = $(sysconfdir)/default/grub.d
platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
starfielddir = $(pkgdatadir)/themes/starfield
CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion
diff -Paur --no-dereference -- grub.upstream/grub-core/lib/libgcrypt-grub/cipher/rijndael.c grub/grub-core/lib/libgcrypt-grub/cipher/rijndael.c
--- grub.upstream/grub-core/lib/libgcrypt-grub/cipher/rijndael.c
+++ grub/grub-core/lib/libgcrypt-grub/cipher/rijndael.c
@ -665,6 +658,18 @@ diff -Paur --no-dereference -- grub.upstream/update-grub grub/update-grub
@@ -0,0 +1,2 @@
+#!/bin/sh -e
+exec grub-mkconfig -o /boot/grub/grub.cfg "$@"
diff -Paur --no-dereference -- grub.upstream/util/bash-completion.d/Makefile.in grub/util/bash-completion.d/Makefile.in
--- grub.upstream/util/bash-completion.d/Makefile.in
+++ grub/util/bash-completion.d/Makefile.in
@@ -1022,7 +1022,7 @@
bash_completion_script = grub
EXTRA_DIST = $(bash_completion_source)
CLEANFILES = $(bash_completion_script) config.log
-bashcompletiondir = $(sysconfdir)/bash_completion.d
+bashcompletiondir = $(sysconfdir)/default/bash_completion.d
bashcompletion_DATA = $(bash_completion_script)
all: all-am
diff -Paur --no-dereference -- grub.upstream/util/getroot.c grub/util/getroot.c
--- grub.upstream/util/getroot.c
+++ grub/util/getroot.c
@ -707,23 +712,6 @@ diff -Paur --no-dereference -- grub.upstream/util/getroot.c grub/util/getroot.c
#else
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
diff -Paur --no-dereference -- grub.upstream/util/grub.d/00_header.in grub/util/grub.d/00_header.in
--- grub.upstream/util/grub.d/00_header.in
+++ grub/util/grub.d/00_header.in
@@ -27,6 +27,13 @@
. "$pkgdatadir/grub-mkconfig_lib"
+if [ -f "/etc/grubpw" ]; then
+ echo 'insmod password_pbkdf2'
+ echo 'set superusers="root"'
+ echo "password_pbkdf2 root $(cat /etc/grubpw)"
+ echo
+fi
+
# Do this as early as possible, since other commands might depend on it.
# (e.g. the `loadfont' command might need lvm or raid modules)
for i in ${GRUB_PRELOAD_MODULES} ; do
diff -Paur --no-dereference -- grub.upstream/util/grub-fstest.c grub/util/grub-fstest.c
--- grub.upstream/util/grub-fstest.c
+++ grub/util/grub-fstest.c
@ -739,7 +727,15 @@ diff -Paur --no-dereference -- grub.upstream/util/grub-fstest.c grub/util/grub-f
diff -Paur --no-dereference -- grub.upstream/util/grub-mkconfig.in grub/util/grub-mkconfig.in
--- grub.upstream/util/grub-mkconfig.in
+++ grub/util/grub-mkconfig.in
@@ -102,27 +102,6 @@
@@ -38,6 +38,7 @@
grub_cfg=""
grub_mkconfig_dir="${sysconfdir}"/grub.d
+grub_mkconfig_default_dir="${sysconfdir}"/default/grub.d
self=`basename $0`
@@ -102,27 +103,6 @@
esac
done
@ -767,6 +763,196 @@ diff -Paur --no-dereference -- grub.upstream/util/grub-mkconfig.in grub/util/gru
set $grub_probe dummy
if test -f "$1"; then
:
@@ -147,8 +127,8 @@
GRUB_FS="$(stat -f --printf=%T / || echo unknown)"
fi
-if test -f ${sysconfdir}/default/grub ; then
- . ${sysconfdir}/default/grub
+if test -f ${sysconfdir}/grub ; then
+ . ${sysconfdir}/grub
fi
# XXX: should this be deprecated at some point?
@@ -211,6 +191,7 @@
GRUB_CMDLINE_NETBSD \
GRUB_CMDLINE_NETBSD_DEFAULT \
GRUB_CMDLINE_GNUMACH \
+ GRUB_CMDLINE_SORTIX \
GRUB_TERMINAL_INPUT \
GRUB_TERMINAL_OUTPUT \
GRUB_SERIAL_COMMAND \
@@ -243,12 +224,23 @@
# DO NOT EDIT THIS FILE
#
# It is automatically generated by $self using templates
-# from ${grub_mkconfig_dir} and settings from ${sysconfdir}/default/grub
+# from ${grub_mkconfig_dir} and ${grub_mkconfig_default_dir}
+# and settings from ${sysconfdir}/grub
#
EOF
-
-for i in "${grub_mkconfig_dir}"/* ; do
+# PATCH: /etc/grub.d overrides /etc/default/grub.d, although it's unsupported to
+# override the 10_sortix file and /etc/grub should be used if possible.
+for n in $({ if [ -d "${grub_mkconfig_dir}" ]; then
+ ls -- "${grub_mkconfig_dir}"
+ fi
+ if [ -d "${grub_mkconfig_default_dir}" ]; then
+ ls -- "${grub_mkconfig_default_dir}"
+ fi; } | LC_ALL=C sort -u); do
+ i="${grub_mkconfig_dir}/$n"
+ if [ ! -f "$i" -a -f "${grub_mkconfig_default_dir}/$n" ]; then
+ i="${grub_mkconfig_default_dir}/$n"
+ fi
case "$i" in
# emacsen backup files. FIXME: support other editors
*~) ;;
@@ -269,7 +261,7 @@
if ! ${grub_script_check} ${grub_cfg}.new; then
# TRANSLATORS: %s is replaced by filename
gettext_printf "Syntax errors are detected in generated GRUB config file.
-Ensure that there are no errors in /etc/default/grub
+Ensure that there are no errors in /etc/grub
and /etc/grub.d/* files or please file a bug report with
%s file attached." "${grub_cfg}.new" >&2
echo >&2
diff -Paur --no-dereference -- grub.upstream/util/grub.d/00_header.in grub/util/grub.d/00_header.in
--- grub.upstream/util/grub.d/00_header.in
+++ grub/util/grub.d/00_header.in
@@ -27,6 +27,13 @@
. "$pkgdatadir/grub-mkconfig_lib"
+if [ -f "/etc/grubpw" ]; then
+ echo 'insmod password_pbkdf2'
+ echo 'set superusers="root"'
+ echo "password_pbkdf2 root $(cat /etc/grubpw)"
+ echo
+fi
+
# Do this as early as possible, since other commands might depend on it.
# (e.g. the `loadfont' command might need lvm or raid modules)
for i in ${GRUB_PRELOAD_MODULES} ; do
diff -Paur --no-dereference -- grub.upstream/util/grub.d/10_sortix.in grub/util/grub.d/10_sortix.in
--- grub.upstream/util/grub.d/10_sortix.in
+++ grub/util/grub.d/10_sortix.in
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+set -e
+
+rm -f "$0.cache.new"
+
+# This script will run on the previous stable release during a sysmerge(8) with
+# a potentially old version of GRUB installed.
+
+# Detect if a system upgrade is ready and emit a bootloader entry using the new
+# script if we're not already it. This script provides a stable interface where
+# the new release helps the old system figure out how to boot the new system.
+PREFIX=
+BOOT_DIR=/boot
+UPGRADE=false
+if [ "$1" = --sysmerge ]; then
+ PREFIX=/sysmerge
+ BOOT_DIR=/boot/sysmerge
+ UPGRADE=true
+elif [ -e /sysmerge/tix/sysmerge.ready ]; then
+ # Write the upgrade menu entry before the old menu entry.
+ /sysmerge/libexec/sysmerge/grub --sysmerge > "$0.cache.new"
+fi
+
+# Allow this script to be run standalone outside of grub-mkconfig.
+if [ -z "$pkgdatadir" -a -f /etc/grub ]; then
+ . /etc/grub
+fi
+
+if [ ! -e "$PREFIX/etc/sortix-release" ]; then
+ exit 0
+fi
+. "$PREFIX/etc/sortix-release"
+
+if $UPGRADE; then
+ PRETTY_NAME="Upgrade to $PRETTY_NAME"
+fi
+
+find_mountpoint() {(
+ FILE="$1"
+ DEVICE=$(grub-probe -t device -- "$FILE")
+ while [ "$FILE" != "/" ]; do
+ PARENT="$(dirname -- "$FILE")"
+ if [ x"$(grub-probe -t device -- "$PARENT")" != x"$DEVICE" ]; then
+ echo "$FILE"
+ exit 0
+ fi
+ FILE="$PARENT"
+ done
+ echo "$FILE"
+ exit 0
+)}
+
+mountpoint_relative() {(
+ REL=""
+ FILE="$1"
+ DEVICE=$(grub-probe -t device -- "$FILE")
+ while [ "$FILE" != "/" ]; do
+ PARENT="$(dirname -- "$FILE")"
+ if [ x"$(grub-probe -t device -- "$PARENT")" != x"$DEVICE" ]; then
+ echo "$REL"
+ exit 0
+ fi
+ REL="/$(basename -- "$FILE")$REL"
+ FILE="$PARENT"
+ done
+ echo "$REL"
+ exit 0
+)}
+
+BOOT_MNT=$(find_mountpoint /boot)
+BOOT_REL=$(mountpoint_relative "$BOOT_DIR")
+OLD_BOOT_REL=$(mountpoint_relative /boot)
+DEVICE=$(grub-probe -t device -- "$BOOT_MNT")
+FS_UUID=$(grub-probe -t fs_uuid -- "$BOOT_MNT")
+HINTS_STRING=$(grub-probe -t hints_string -- "$BOOT_MNT")
+PARTMAP=$(grub-probe -t partmap -- "$BOOT_MNT")
+FS=$(grub-probe -t fs -- "$BOOT_MNT")
+
+echo "Found $PRETTY_NAME on $DEVICE" >&2
+cat >> "$0.cache.new" << EOF
+menuentry "$PRETTY_NAME (on $DEVICE)" --unrestricted {
+ insmod part_$PARTMAP
+ insmod $FS
+ search --no-floppy --fs-uuid --set=root $HINTS_STRING $FS_UUID
+ multiboot $BOOT_REL/sortix.bin $GRUB_CMDLINE_SORTIX
+ module $OLD_BOOT_REL/random.seed --random-seed
+ module $BOOT_REL/sortix.initrd
+}
+EOF
+mv "$0.cache.new" "$0.cache"
+cat "$0.cache"
diff -Paur --no-dereference -- grub.upstream/util/grub.d/README grub/util/grub.d/README
--- grub.upstream/util/grub.d/README
+++ grub/util/grub.d/README
@@ -1,11 +1,15 @@
-
-All executable files in this directory are processed in shell expansion order.
+All executable files in /etc/grub.d and /etc/grub.d/default are processed in
+shell expansion order.
00_*: Reserved for 00_header.
10_*: Native boot entries.
20_*: Third party apps (e.g. memtest86+).
+Files in /etc/grub.d override files in /etc/grub.d/default if they exist. It is
+unsupported to override the native bootloader file 10_sortix since the
+configuration will be updated across releases
+
The number namespace in-between is configurable by system installer and/or
administrator. For example, you can add an entry to boot another OS as
01_otheros, 11_otheros, etc, depending on the position you want it to occupy in
-the menu; and then adjust the default setting via /etc/default/grub.
+the menu; and then adjust the default setting via /etc/grub.
diff -Paur --no-dereference -- grub.upstream/util/misc.c grub/util/misc.c
--- grub.upstream/util/misc.c
+++ grub/util/misc.c

View File

@ -1,6 +1,5 @@
#!/bin/sh -e
cp update-grub "$TIX_INSTALL_DIR$EXEC_PREFIX/sbin/update-grub"
cp 10_sortix "$TIX_INSTALL_DIR$PREFIX/etc/grub.d/10_sortix"
if [ ! -e "$TIX_INSTALL_DIR$PREFIX/share/grub/unicode.pf2" ]; then
# Cheat as I'm not sure how to get this when cross-building.
[ -e /share/grub/unicode.pf2 ] &&

View File

@ -90,7 +90,7 @@ and if
is set to
.Sy no ,
then regenerate
.Pa /etc/grub.d/10_sortix.cache .
.Pa /etc/default/grub.d/10_sortix.cache .
.El
.Pp
The defaults will be used if

View File

@ -69,6 +69,74 @@ releasing Sortix x.y, foo." to allow the maintainer to easily
.Xr grep 1
for it after a release.
.Sh CHANGES
.Ss Support system upgrades and configuration in GRUB
The GRUB configuration now implements the
.Pa /etc
and
.Pa /etc/default
configuration split per
.Xr hier 7
and
.Xr sysmerge 8
now collaborates with system upgrades to boot them correctly.
Installations with manually configured bootloaders may need updating.
.Pp
Notably
.Pa /etc/default/grub
has been moved to
.Pa /etc/grub
since it is owned by the system administrator and there is no counterpart with
operating system provided defaults.
.Pp
Additionally
.Pa /etc/grub.d
has been moved into
.Pa /etc/default/grub.d
since it provides operating system defaults.
The system administrator can now create the
.Pa /etc/grub.d
directory manually to override files in
.Pa /etc/default/grub.d ,
although overriding
.Pa 10_sortix
is unsupported.
.Pp
.Pa 10_sortix
now supports the
.Pa GRUB_CMDLINE_SORTIX
variable in
.Pa /etc/grub
to specify kernel command line options.
.Pp
.Xr sysmerge 8
now colloborates with the
.Xr update-initrd 8
and
.Pa 10_sortix
scripts in the new system to prepare the upgrade system's kernel files in
.Pa /boot/sysmerge/ .
If the GRUB bootloader is accepted, then
.Pa /boot/grub/grub.cfg
is regenerated with a menu entry to perform the upgrade.
The
.Pa /boot/sortix.bin
and
.Pa /boot/sortix.initrd
files are no longer replaced with the new versions and continue to boot the old
system without upgrading.
Any manual bootloader configuration must be configured to instead load the
kernel and initrd from
.Pa /boot/sysmerge/
(if they exist).
The
.Pa /etc/default/grub.d/10_sortix.cache
file will demonstrate how to boot the new system using GRUB after starting a
.Xr sysmerge 8
(if the grub port is installed).
.Pp
An upgrade hook will delete the obsolete stale
.Pa /etc/grub.d/10_sortix.cache
file.
.Ss Third generation Tix
The tix binary package format has upgraded from generation 2 to 3 and has a new
internal layout that can be directly extracted into the filesystem.
@ -315,7 +383,7 @@ The kernel will issue a security warning if it was booted without a random seed,
unless the kernel command line contains
.Fl \-no-random-seed .
The GRUB port has been updated with an improved
.Pa /etc/grub.d/10_sortix
.Pa /etc/default/grub.d/10_sortix
script that will automatically emit the appropriate GRUB commands.
.Pp
Users using the included GRUB will need to update to the latest GRUB port
@ -341,9 +409,9 @@ If the GRUB port is installed, but not used, then if that port is updated with
or
.Xr sysmerge 8
or manually, the
.Pa /etc/grub.d/10_sortix
.Pa /etc/default/grub.d/10_sortix
script can be invoked, which will generate a
.Pa /etc/grub.d/10_sortix.cache
.Pa /etc/default/grub.d/10_sortix.cache
fragment that can be spliced into the configuration of another GRUB
installation.
.Pp

View File

@ -6,7 +6,7 @@
.Nd layout of filesystems
.Sh DESCRIPTION
The filesystem hierarchy is as follows:
.Bl -tag -width "1234567891012"
.Bl -tag -width "/boot/sysmerge"
.It Pa /
Root directory.
.It Pa /bin
@ -16,6 +16,10 @@ Boot programs,
.Xr kernel 7 ,
.Xr initrd 7 ,
bootloader.
.It Pa /boot/sysmerge
Temporary area for
.Xr sysmerge 8
delayed upgrades.
.It Pa /dev
Devices.
.It Pa /etc

View File

@ -529,7 +529,7 @@ If the included GRUB bootloader is used, after making the above edit, run
.Xr update-grub 8
within the new installation to regenerate the bootloader configuration.
Note that
.Pa /etc/grub.d/10_sortix
.Pa /etc/default/grub.d/10_sortix
is part of the GRUB package and local changes will be undone when the GRUB
package is updated or reinstalled, in which case you must make this change again
and run
@ -537,12 +537,12 @@ and run
again.
.Pp
If the included GRUB bootloader is not used, but instead the
.Pa /etc/grub.d/10_sortix.cache
.Pa /etc/default/grub.d/10_sortix.cache
fragment is spliced into another GRUB installation, make the above change and
then run the
.Pa /etc/grub.d/10_sortix
.Pa /etc/default/grub.d/10_sortix
command and use the freshly regenerated
.Pa /etc/grub.d/10_sortix.cache
.Pa /etc/default/grub.d/10_sortix.cache
fragment instead.
.Sh SEE ALSO
.Xr chkblayout 1 ,

View File

@ -46,6 +46,9 @@ install: all
install sysinstall $(DESTDIR)$(SBINDIR)
install sysmerge $(DESTDIR)$(SBINDIR)
install sysupgrade $(DESTDIR)$(SBINDIR)
mkdir -p $(DESTDIR)$(LIBEXECDIR)/sysmerge
install prepare $(DESTDIR)$(LIBEXECDIR)/sysmerge
install grub $(DESTDIR)$(LIBEXECDIR)/sysmerge
mkdir -p $(DESTDIR)$(MANDIR)/man8
cp sysinstall.8 $(DESTDIR)$(MANDIR)/man8/sysinstall.8
cp sysmerge.8 $(DESTDIR)$(MANDIR)/man8/sysmerge.8
@ -59,6 +62,7 @@ install: all
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-passwd
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-group
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-tix3g
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-grub-cache
sysinstall: $(SYSINSTALL_OBJS)
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount -ldisplay

29
sysinstall/grub Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
# Copyright (c) 2023 Jonas 'Sortie' Termansen.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# grub
# Output the GRUB configuration needed to boot the sysmerge(8) --wait upgrade.
# This script will run on the previous stable release during a sysmerge(8) as a
# high-level entry point to help the previous system generate the grub config to
# boot the new system. This script minimizes the interface between the old and
# new system to allow change. This script is ordinarily invoked by 10_sortix
# from the grub port.
set -e
# The old system has copied the new kernel and initrd files from /sysmerge/boot
# to /boot/sysmerge and we need to configure grub to boot them.
/sysmerge/etc/default/grub.d/10_sortix --sysmerge

View File

@ -463,6 +463,28 @@ void upgrade_prepare(const struct release* old_release,
// Delay deleting installed.list since it's needed for the upgrade.
hook_want_finalization(target_prefix, "sortix-1.1-tix3g");
}
// TODO: After releasing Sortix 1.1, remove this compatibility.
if ( hook_needs_to_be_run(source_prefix, target_prefix,
"sortix-1.1-grub-cache") )
{
char* path = join_paths(target_prefix, "/etc/grub.d/10_sortix.cache");
if ( !path )
{
warn("malloc");
_exit(2);
}
if ( !access_or_die(path, F_OK) )
{
printf(" - Removing /etc/grub.d/10_sortix.cache...\n");
if ( unlink(path) < 0 )
{
warn("unlink: %s", path);
_exit(2);
}
}
free(path);
}
}
void upgrade_finalize(const struct release* old_release,

27
sysinstall/prepare Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Copyright (c) 2023 Jonas 'Sortie' Termansen.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# prepare
# Prepare a sysmerge(8) --wait upgrade on the next boot.
# This script will run on the previous stable release during a sysmerge(8) as a
# high-level entry point to help the previous system generate the kernel and
# initrd files for the new system. This script minimizes the interface between
# the old and new system to allow change. The working directory is the directory
# the sysmerge upgrade is pending inside, usually /sysmerge.
set -e
/sysmerge/sbin/update-initrd --sysmerge

View File

@ -991,12 +991,13 @@ int main(void)
execute((const char*[]) { "chroot", "-d", ".", "update-grub", NULL },
"_eqQ");
}
else if ( access_or_die("/etc/grub.d/10_sortix", F_OK) == 0 )
else if ( access_or_die("/etc/default/grub.d/10_sortix", F_OK) == 0 )
{
// Help dual booters by making /etc/grub.d/10_sortix.cache.
// Help dual booters by making /etc/grub.d/default/10_sortix.cache.
printf(" - Creating bootloader fragment...\n");
execute((const char*[]) { "chroot", "-d", ".",
"/etc/grub.d/10_sortix", NULL }, "_eq");
"/etc/grub.d/default/10_sortix",
NULL }, "_eq");
}
printf(" - Finishing installation...\n");
_exit(0);
@ -1530,8 +1531,9 @@ int main(void)
if ( strcasecmp(accept_grub, "no") == 0 )
text("You did not accept a bootloader and need to set up bootloading "
"yourself. /etc/grub.d/10_sortix.cache is a GRUB configuration "
"fragment that boots the newly installed system.\n\n");
"yourself. /etc/default/grub.d/10_sortix.cache is a GRUB "
"configuration fragment that boots the newly installed system."
"\n\n");
text("Upon boot, you'll be greeted with a login screen. Enter your "
"credentials to get a command line. Login as user 'poweroff' as "

View File

@ -124,52 +124,50 @@ This option is implied unless
is passed.
.It Fl w , Fl \-wait
Wait until the next boot to complete the upgrade, rather than finishing it now.
This installs into the
The upgrade is installed into the
.Pa /sysmerge
directory instead and replaces the
directory instead, with the new kernel and initrd files in
.Pa /boot/sysmerge .
The new
.Xr kernel 7
with the new kernel
and
has a new
.Xr initrd 7
with an initrd that runs
that runs
.Sy /sysmerge/sbin/sysmerge --booting
on boot through the
.Sy chain-merge
.Xr init 8
boot target.
Backups are made of the
.Xr kernel 7
and
.Xr initrd 7
such that the operation can be rolled back.
boot target, which performs the operating system upgrade.
The bootloader configuration is regenerated with a menu option to perform
the upgrade if grub is enabled in
.Xr upgrade.conf 5 ,
otherwise the
.Pa /etc/default/grub.d/10_sortix.cache
bootloader fragment can be used to manually bootload the upgrade.
.El
.Sh FILES
.Bl -tag -width "/boot/sortix.initrd.sysmerge.orig" -compact
.Bl -tag -width "/etc/default/grub.d/10_sortix.cache" -compact
.It Pa /boot/sortix.bin
system
.Xr kernel 7
.It Pa /boot/sortix.bin.sysmerge.orig
system
.Xr kernel 7
(backup)
Old system
.Xr kernel 7 .
.It Pa /boot/sortix.initrd
system
.Xr initrd 7
.It Pa /boot/sortix.initrd.sysmerge.orig
system
.Xr initrd 7
(backup)
Old system
.Xr initrd 7 .
.It Pa /boot/sysmerge/
New system kernel and initrd files.
.It Pa /etc/default/grub.d/10_sortix.cache
GRUB configuration fragment that boots the new system.
.It Pa /etc/machine
processor platform of this installation
Processor platform of this installation.
.It Pa /etc/sortix-release
the current system release
The current system release.
.It Pa /etc/upgrade.conf
controls the bootloader upgrade behavior (see
.Xr upgrade.conf 5 )
.It Pa /share/sysinstall/hooks
Controls the bootloader upgrade behavior (see
.Xr upgrade.conf 5 ) .
.It Pa /share/sysinstall/hooks/
A file per upgrade hook indicating that it doesn't need to be run.
.It Pa /sysmerge
pending upgrade is stored here
.It Pa /sysmerge/
The pending systen upgrade is stored here.
.El
.Sh SEE ALSO
.Xr development 7 ,

View File

@ -86,20 +86,32 @@ static bool is_partition_name(const char* path)
static bool has_pending_upgrade(const char* target)
{
char* kernel = join_paths(target, "boot/sortix.bin.sysmerge.orig");
char* initrd = join_paths(target, "boot/sortix.initrd.sysmerge.orig");
char* sysmerge = join_paths(target, "sysmerge");
if ( !kernel || !initrd || !sysmerge )
char* boot_sysmerge = join_paths(target, "boot/sysmerge");
if ( !sysmerge || !boot_sysmerge )
err(2, "malloc");
bool result = access_or_die(kernel, F_OK) == 0 ||
access_or_die(initrd, F_OK) == 0 ||
access_or_die(sysmerge, F_OK) == 0;
free(kernel);
free(initrd);
bool result = access_or_die(sysmerge, F_OK) == 0 ||
access_or_die(boot_sysmerge, F_OK) == 0;
free(sysmerge);
free(boot_sysmerge);
return result;
}
static void update_grub(struct conf* conf, const char* target)
{
if ( conf->grub )
{
printf(" - Configuring bootloader...\n");
execute((const char*[]) { "update-grub", NULL }, "ceqQ", target);
}
else if ( access_or_die("/etc/default/grub.d/10_sortix", F_OK) == 0 )
{
printf(" - Creating bootloader fragment...\n");
execute((const char*[]) { "/etc/default/grub.d/10_sortix", NULL },
"ceq", target);
}
}
int main(int argc, char* argv[])
{
setvbuf(stdout, NULL, _IOLBF, 0); // Pipes.
@ -207,20 +219,24 @@ int main(int argc, char* argv[])
if ( !has_system )
system = false;
struct conf conf;
conf_init(&conf);
char* conf_path = join_paths(target, "etc/upgrade.conf");
if ( !conf_path )
err(2, "malloc");
if ( !conf_load(&conf, conf_path) && errno != ENOENT )
err(2, conf_path);
bool did_cancel = false;
if ( !no_cancel && has_pending_upgrade(target) )
{
char* kernel = join_paths(target, "boot/sortix.bin.sysmerge.orig");
char* kernel_real = join_paths(target, "boot/sortix.bin");
char* initrd = join_paths(target, "boot/sortix.initrd.sysmerge.orig");
char* initrd_real = join_paths(target, "boot/sortix.initrd");
char* sysmerge = join_paths(target, "sysmerge");
if ( !kernel || !kernel_real || !initrd || !initrd_real || !sysmerge )
char* boot_sysmerge = join_paths(target, "boot/sysmerge");
if ( !sysmerge || !boot_sysmerge )
err(2, "malloc");
rename(kernel, kernel_real);
rename(initrd, initrd_real);
execute((const char*[]) { "rm", "-rf", "--", sysmerge, NULL }, "");
execute((const char*[]) { "update-initrd", NULL }, "ce", target);
execute((const char*[]) { "rm", "-rf", "--", boot_sysmerge, NULL }, "");
update_grub(&conf, target);
printf("Cancelled pending system upgrade.\n");
did_cancel = true;
}
@ -290,14 +306,6 @@ int main(int argc, char* argv[])
// TODO: Check for version (skipping, downgrading).
struct conf conf;
conf_init(&conf);
char* conf_path = join_paths(target, "etc/upgrade.conf");
if ( !conf_path )
err(2, "malloc");
if ( !conf_load(&conf, conf_path) && errno != ENOENT )
err(2, conf_path);
bool can_run_new_abi =
abi_compatible(new_release.abi_major, new_release.abi_minor,
old_release.abi_major, old_release.abi_minor);
@ -416,14 +424,13 @@ int main(int argc, char* argv[])
char* system_path = join_paths(target, "sysmerge/tix/sysmerge.system");
char* ports_path = join_paths(target, "sysmerge/tix/sysmerge.ports");
char* full_path = join_paths(target, "sysmerge/tix/sysmerge.full");
char* kernel = join_paths(target, "boot/sortix.bin.sysmerge.orig");
char* kernel_real = join_paths(target, "boot/sortix.bin");
char* kernel_new = join_paths(target, "sysmerge/boot/sortix.bin");
char* initrd = join_paths(target, "boot/sortix.initrd.sysmerge.orig");
char* initrd_real = join_paths(target, "boot/sortix.initrd");
if ( !system_path || !ports_path || !full_path || !kernel ||
!kernel_real || !kernel_new || !initrd || !initrd_real )
char* ready_path = join_paths(target, "sysmerge/tix/sysmerge.ready");
char* sysmerge_boot = join_paths(target, "sysmerge/boot");
char* boot_sysmerge = join_paths(target, "boot/sysmerge");
if ( !system_path || !ports_path || !full_path || !ready_path ||
!sysmerge_boot || !boot_sysmerge )
err(2, "malloc");
if ( full )
{
int fd = open(full_path, O_WRONLY | O_CREAT);
@ -445,11 +452,25 @@ int main(int argc, char* argv[])
err(2, "%s", ports_path);
close(fd);
}
execute((const char*[]) { "cp", kernel_real, kernel, NULL }, "e");
execute((const char*[]) { "cp", initrd_real, initrd, NULL }, "e");
execute((const char*[]) { "cp", kernel_new, kernel_real, NULL }, "e");
execute((const char*[]) { "/sysmerge/sbin/update-initrd", NULL }, "ce",
target);
// Generate the new initrd in /sysmerge/boot.
execute((const char*[]) { "/sysmerge/libexec/sysmerge/prepare",
NULL }, "ce", target);
// Move the kernel and initrd files to the boot partition where the
// bootloader is guaranteed to be able to read them.
execute((const char*[]) { "rm", "-rf", "--", boot_sysmerge,
NULL }, "e");
execute((const char*[]) { "cp", "-RT", "--", sysmerge_boot,
boot_sysmerge, NULL }, "e");
// Signal the sysmerge upgrade is ready and isn't partial.
int fd = open(ready_path, O_WRONLY | O_CREAT);
if ( fd < 0 )
err(2, "%s", ready_path);
close(fd);
update_grub(&conf, target);
printf("The system will be upgraded to %s on the next boot.\n",
new_release.pretty_name);
@ -477,21 +498,20 @@ int main(int argc, char* argv[])
return 0;
}
// Remove the upgrade readiness marker now that the upgrade has gone through
// such that the bootloader configuration and initrds don't try to do the
// upgrade again.
if ( has_system && booting )
{
char* kernel = join_paths(target, "boot/sortix.bin.sysmerge.orig");
char* initrd = join_paths(target, "boot/sortix.initrd.sysmerge.orig");
char* sysmerge = join_paths(target, "sysmerge");
if ( !kernel || !initrd || !sysmerge )
char* ready_path = join_paths(target, "sysmerge/tix/sysmerge.ready");
if ( !ready_path )
err(2, "malloc");
unlink(kernel);
unlink(initrd);
execute((const char*[]) { "rm", "-rf", "--", sysmerge, NULL }, "");
free(kernel);
free(initrd);
free(sysmerge);
unlink(ready_path);
free(ready_path);
}
// Update the initrd and bootloader. The new bootloader config won't refer
// to the upgrade as it's complete and the marker is gone.
if ( has_system && access_or_die("/etc/fstab", F_OK) == 0 )
{
printf(" - Creating initrd...\n");
@ -510,23 +530,40 @@ int main(int argc, char* argv[])
err(2, "Failed to find device of filesystem: %s", boot_path);
close(boot_fd);
free(boot_path);
// TODO: A better design for finding the parent block device of a
// partition without scanning every block device.
// TODO: A better design for finding the parent block device.
if ( is_partition_name(boot_device) )
*strrchr(boot_device, 'p') = '\0';
printf(" - Installing bootloader...\n");
execute((const char*[]) { "grub-install", boot_device,
NULL }, "ceqQ", target);
NULL }, "ceqQ", target);
free(boot_device);
printf(" - Configuring bootloader...\n");
execute((const char*[]) { "update-grub", NULL }, "ceqQ", target);
}
else if ( access_or_die("/etc/grub.d/10_sortix", F_OK) == 0 )
{
printf(" - Creating bootloader fragment...\n");
execute((const char*[]) { "/etc/grub.d/10_sortix", NULL }, "ceq",
target);
}
update_grub(&conf, target);
}
// Finally clean up /sysmerge and /boot/sysmerge. They were left alone so
// the system remained bootable with the idempotent upgrade if it failed
// midway. Okay there's a bit of race conditions in grub-install, though the
// replacement of grub.cfg is atomic. Everything now points into the new
// system and nothing refers to the sysmerge directories.
if ( has_system && booting )
{
// TODO: After releasing Sortix 1.1, remove sysmerge.orig compatibility.
char* kernel = join_paths(target, "boot/sortix.bin.sysmerge.orig");
char* initrd = join_paths(target, "boot/sortix.initrd.sysmerge.orig");
char* sysmerge = join_paths(target, "sysmerge");
char* boot_sysmerge = join_paths(target, "boot/sysmerge");
if ( !kernel || !initrd || !sysmerge || !boot_sysmerge )
err(2, "malloc");
unlink(kernel);
unlink(initrd);
execute((const char*[]) { "rm", "-rf", "--", sysmerge, NULL }, "");
execute((const char*[]) { "rm", "-rf", "--", boot_sysmerge, NULL }, "");
free(kernel);
free(initrd);
free(sysmerge);
free(boot_sysmerge);
}
if ( new_release.pretty_name )

View File

@ -920,12 +920,13 @@ int main(void)
"_eqQ");
}
else if ( conf.system &&
access_or_die("etc/grub.d/10_sortix", F_OK) == 0 )
access_or_die("etc/default/grub.d/10_sortix", F_OK) == 0 )
{
// Help dual booters by making /etc/grub.d/10_sortix.cache.
// Help dual booters by making /etc/default/grub.d/10_sortix.cache.
printf(" - Creating bootloader fragment...\n");
execute((const char*[]) { "chroot", "-d", ".",
"/etc/grub.d/10_sortix", NULL }, "_eq");
"/etc/grub.d/default/10_sortix", NULL },
"_eq");
}
printf(" - Finishing upgrade...\n");
_exit(0);

View File

@ -16,9 +16,12 @@
# update-initrd
# Generate an initrd(7) that locates and chain boots the real root filesystem.
# This script will run on the previous stable release during a sysmerge(8).
set -e
sysroot=
sysmerge=false
dashdash=
previous_option=
@ -35,6 +38,7 @@ for argument do
esac
case $dashdash$argument in
--) dashdash=yes ;;
--sysmerge) sysmerge=true ;;
--sysroot=*) sysroot=$parameter ;;
--sysroot) previous_option=sysroot ;;
-*) echo "$0: unrecognized option $argument" >&2
@ -49,17 +53,20 @@ if test -n "$previous_option"; then
exit 1
fi
sysmerge=false
exec_prefix="$sysroot"
if [ -d "$sysroot/sysmerge" ]; then
# If an upgrade is pending, invoke the update-initrd of the new system, if
# we're not already it.
if [ "$(realpath -- "$(which -- "$0")")" != \
"$(realpath -- "$sysroot/sysmerge/sbin/update-initrd")" ]; then
exec "$sysroot/sysmerge/sbin/update-initrd" "$@"
fi
root="$sysroot"
output="$sysroot"
if $sysmerge; then
root="$sysroot/sysmerge"
output="$root"
# TODO: After releasing Sortix 1.1, remove the check for /sysmerge as the old
# update-initrd will invoke the newer version and expect the new version
# to notice that it is the version in /sysmerge. However, write the new
# initrd to /boot rather than /sysmerge/boot since 1.0 doesn't implement
# the new scheme.
elif [ -e /sysmerge -a "$0" = /sysmerge/sbin/update-initrd ]; then
sysmerge=true
exec_prefix="$sysroot/sysmerge"
root="$sysroot/sysmerge"
output="$sysroot"
fi
if [ ! -e "$sysroot/etc/fstab" ]; then
echo "$0: $sysroot/etc/fstab: Need a filesystem table to make an initrd" >&2
@ -69,10 +76,10 @@ tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT HUP INT QUIT TERM
mkdir "$tmp/bin"
mkdir "$tmp/sbin"
cp "$exec_prefix/sbin/init" "$tmp/sbin"
cp "$exec_prefix/sbin/extfs" "$tmp/sbin"
test -f "$exec_prefix/sbin/fsck.ext2" &&
cp "$exec_prefix/sbin/fsck.ext2" "$tmp/sbin"
cp "$root/sbin/init" "$tmp/sbin"
cp "$root/sbin/extfs" "$tmp/sbin"
test -f "$root/sbin/fsck.ext2" &&
cp "$root/sbin/fsck.ext2" "$tmp/sbin"
mkdir "$tmp/etc"
cp "$sysroot/etc/fstab" "$tmp/etc/fstab"
mkdir "$tmp/etc/init"
@ -85,7 +92,7 @@ else
require chain exit-code
EOF
fi
mkdir -p "$sysroot/boot"
mkdir -p "$output/boot"
LC_AL=C ls -A "$tmp" |
tar -C "$tmp" -cf "$sysroot/boot/sortix.initrd" \
tar -C "$tmp" -cf "$output/boot/sortix.initrd" \
--numeric-owner --owner=0 --group=0 -T -

View File

@ -6,6 +6,7 @@
.Nd generate initialization ramdisk
.Sh SYNOPSIS
.Nm update-initrd
.Op Fl \-sysmerge
.Op Fl \-sysroot Ns "=" Ns Ar sysroot
.Sh DESCRIPTION
.Nm update-initrd
@ -31,19 +32,20 @@ should be regenerated by invoking
.Nm .
.Pp
.Nm
is aware of
.Xr sysmerge 8
pending upgrades and will instead invoke the new
.Nm
in
.Pa /sysmerge
if an upgrade is pending.
.Nm
is written as a script so the initrd of the new system can produced even
across incompatible ABI changes.
.Pp
The options are as follows:
.Bl -tag -width "12345678"
.It Fl \-sysmerge
Generate an
.Xr initrd 7
for the pending upgrade in
.Pa /sysmerge
inside the sysroot.
This must be used in combination with invoking the matching
.Pa /sysmerge/sbin/update-initrd
program directly for forward compatibility.
.It Fl \-sysroot Ns "=" Ns Ar sysroot
Rather than generating an
.Xr initrd 7