mirror of
https://github.com/clearlinux/clr-boot-manager.git
synced 2026-09-08 06:31:47 +00:00
Merge branch 'kai/shim-systemd'
This commit is contained in:
+2
-1
@@ -31,6 +31,8 @@ addons:
|
||||
- lcov
|
||||
- llvm-3.8
|
||||
- valgrind
|
||||
- gnu-efi
|
||||
- libefivar-dev
|
||||
|
||||
|
||||
before_install:
|
||||
@@ -42,7 +44,6 @@ script:
|
||||
- ./configure --enable-coverage && make && make check && make distcheck && make check-valgrind
|
||||
- clang-format-3.8 -i $(find . -name '*.[ch]') && git diff --exit-code
|
||||
|
||||
|
||||
after_success:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- lcov --compat-libtool --directory . --capture --output-file coverage.info
|
||||
|
||||
+285
-256
@@ -2,73 +2,78 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
|
||||
|
||||
EXTRA_DIST = ${top_srcdir}/README.md \
|
||||
${top_srcdir}/LICENSE.LGPL2.1 \
|
||||
${top_srcdir}/HACKING \
|
||||
${top_srcdir}/findstatic.pl \
|
||||
${top_srcdir}/tests/data/blobfile \
|
||||
${top_srcdir}/tests/data/match \
|
||||
${top_srcdir}/tests/data/match1 \
|
||||
${top_srcdir}/tests/data/nomatch1 \
|
||||
${top_srcdir}/tests/data/nomatch2 \
|
||||
${top_srcdir}/tests/data/clear.os-release \
|
||||
${top_srcdir}/tests/data/solus.os-release \
|
||||
${top_srcdir}/tests/data/cmdline/comments \
|
||||
${top_srcdir}/tests/data/cmdline/mangledmess \
|
||||
${top_srcdir}/tests/data/cmdline/multi \
|
||||
${top_srcdir}/tests/data/cmdline/oneline \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/00_empty.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/00_newline.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/10_first.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/20_second.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/30_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/10_first.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/20_second.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/30_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/00_empty.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/00_newline.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/10_first.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/20_second.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/30_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/40_masked.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/10_local_first.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/20_local_second.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/30_local_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/40_masked.conf \
|
||||
${top_srcdir}/tests/data/gptmbr.bin \
|
||||
${top_srcdir}/tests/data/gptmbr.bin.v2 \
|
||||
${top_srcdir}/sgcheck.suppressions \
|
||||
${top_srcdir}/data/clr-boot-manager-booted.service \
|
||||
${top_srcdir}/man/clr-boot-manager.1
|
||||
EXTRA_DIST = \
|
||||
${top_srcdir}/README.md \
|
||||
${top_srcdir}/LICENSE.LGPL2.1 \
|
||||
${top_srcdir}/HACKING \
|
||||
${top_srcdir}/findstatic.pl \
|
||||
${top_srcdir}/tests/data/blobfile \
|
||||
${top_srcdir}/tests/data/match \
|
||||
${top_srcdir}/tests/data/match1 \
|
||||
${top_srcdir}/tests/data/nomatch1 \
|
||||
${top_srcdir}/tests/data/nomatch2 \
|
||||
${top_srcdir}/tests/data/clear.os-release \
|
||||
${top_srcdir}/tests/data/solus.os-release \
|
||||
${top_srcdir}/tests/data/cmdline/comments \
|
||||
${top_srcdir}/tests/data/cmdline/mangledmess \
|
||||
${top_srcdir}/tests/data/cmdline/multi \
|
||||
${top_srcdir}/tests/data/cmdline/oneline \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/00_empty.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/00_newline.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/10_first.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/20_second.conf \
|
||||
${top_srcdir}/tests/data/etc/kernel/cmdline.d/30_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/10_first.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/20_second.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/30_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/00_empty.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/00_newline.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/10_first.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/20_second.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/30_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/40_masked.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/10_local_first.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/20_local_second.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/30_local_third.conf \
|
||||
${top_srcdir}/tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/40_masked.conf \
|
||||
${top_srcdir}/tests/data/gptmbr.bin \
|
||||
${top_srcdir}/tests/data/gptmbr.bin.v2 \
|
||||
${top_srcdir}/sgcheck.suppressions \
|
||||
${top_srcdir}/data/clr-boot-manager-booted.service \
|
||||
${top_srcdir}/man/clr-boot-manager.1
|
||||
|
||||
NULL =
|
||||
CLEANFILES =
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--with-systemdsystemunitdir="${distdir}/${libdir}/systemd/system"
|
||||
--with-systemdsystemunitdir="${distdir}/${libdir}/systemd/system"
|
||||
|
||||
|
||||
AM_CFLAGS = -fstack-protector -Wall -pedantic \
|
||||
-Wstrict-prototypes -Wundef -fno-common \
|
||||
-Werror-implicit-function-declaration \
|
||||
-Wformat -Wformat-security -Werror=format-security \
|
||||
-Wconversion -Wunused-variable -Wunreachable-code \
|
||||
-Wall -W -D_FORTIFY_SOURCE=2 \
|
||||
-Wno-missing-field-initializers \
|
||||
-std=c11 \
|
||||
-DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
AM_CFLAGS = -fstack-protector -Wall -pedantic \
|
||||
-Wstrict-prototypes -Wundef -fno-common \
|
||||
-Werror-implicit-function-declaration \
|
||||
-Wformat -Wformat-security -Werror=format-security \
|
||||
-Wconversion -Wunused-variable -Wunreachable-code \
|
||||
-Wall -W -D_FORTIFY_SOURCE=2 \
|
||||
-Wno-missing-field-initializers \
|
||||
-std=c11 \
|
||||
-DSYSCONFDIR=\"$(sysconfdir)\" \
|
||||
-D_POSIX_C_SOURCE=201112L
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I $(top_srcdir)/src \
|
||||
-I $(top_srcdir)/src/bootman \
|
||||
-I $(top_srcdir)/src/cli \
|
||||
-I $(top_srcdir)/src/bootloaders \
|
||||
-I $(top_srcdir)/src/lib \
|
||||
-I $(top_srcdir)/src/libnica/src/include \
|
||||
-DTOP_DIR=\"$(abs_top_srcdir)\" \
|
||||
-DTOP_BUILD_DIR=\"$(abs_top_builddir)\"
|
||||
AM_CPPFLAGS = \
|
||||
-I $(top_srcdir)/src \
|
||||
-I $(top_srcdir)/src/bootman \
|
||||
-I $(top_srcdir)/src/cli \
|
||||
-I $(top_srcdir)/src/bootloaders \
|
||||
-I $(top_srcdir)/src/lib \
|
||||
-I $(top_srcdir)/src/libnica/src/include \
|
||||
-isystem @efivar@ \
|
||||
-isystem @gnuefi@ \
|
||||
-isystem @gnuefi@/@host_cpu@ \
|
||||
-DTOP_DIR=\"$(abs_top_srcdir)\" \
|
||||
-DTOP_BUILD_DIR=\"$(abs_top_builddir)\"
|
||||
|
||||
AUTOMAKE_OPTIONS = color-tests parallel-tests
|
||||
|
||||
@@ -89,68 +94,76 @@ noinst_LTLIBRARIES = \
|
||||
|
||||
bin_PROGRAMS = clr-boot-manager
|
||||
|
||||
libcbm_la_SOURCES = \
|
||||
src/bootloaders/bootloader.h \
|
||||
src/bootloaders/systemd-class.h \
|
||||
src/bootloaders/systemd-class.c \
|
||||
src/bootloaders/systemd-boot.c \
|
||||
src/bootloaders/grub2.c \
|
||||
src/bootloaders/gummiboot.c \
|
||||
src/bootloaders/goofiboot.c \
|
||||
src/bootloaders/syslinux.c \
|
||||
src/bootman/bootman.h \
|
||||
src/bootman/bootman_private.h \
|
||||
src/bootman/bootman.c \
|
||||
src/bootman/kernel.c \
|
||||
src/bootman/sysconfig.c \
|
||||
src/bootman/timeout.c \
|
||||
src/bootman/update.c \
|
||||
src/lib/blkid_stub.h \
|
||||
src/lib/blkid_stub.c \
|
||||
src/lib/cmdline.h \
|
||||
src/lib/cmdline.c \
|
||||
src/lib/files.h \
|
||||
src/lib/files.c \
|
||||
src/lib/os-release.h \
|
||||
src/lib/os-release.c \
|
||||
src/lib/log.h \
|
||||
src/lib/log.c \
|
||||
src/lib/probe.h \
|
||||
src/lib/probe.c \
|
||||
src/lib/system_stub.h \
|
||||
src/lib/system_stub.c \
|
||||
src/lib/writer.h \
|
||||
src/lib/writer.c \
|
||||
src/lib/util.h \
|
||||
src/lib/util.c
|
||||
SOURCE_FILES = \
|
||||
src/bootloaders/bootloader.h \
|
||||
src/bootloaders/systemd-class.h \
|
||||
src/bootloaders/systemd-class.c \
|
||||
src/bootloaders/shim-systemd.c \
|
||||
src/bootloaders/systemd-boot.c \
|
||||
src/bootloaders/grub2.c \
|
||||
src/bootloaders/gummiboot.c \
|
||||
src/bootloaders/goofiboot.c \
|
||||
src/bootloaders/syslinux.c \
|
||||
src/bootman/bootman.h \
|
||||
src/bootman/bootman_private.h \
|
||||
src/bootman/bootman.c \
|
||||
src/bootman/kernel.c \
|
||||
src/bootman/sysconfig.c \
|
||||
src/bootman/timeout.c \
|
||||
src/bootman/update.c \
|
||||
src/lib/blkid_stub.h \
|
||||
src/lib/blkid_stub.c \
|
||||
src/lib/cmdline.h \
|
||||
src/lib/cmdline.c \
|
||||
src/lib/files.h \
|
||||
src/lib/files.c \
|
||||
src/lib/os-release.h \
|
||||
src/lib/os-release.c \
|
||||
src/lib/log.h \
|
||||
src/lib/log.c \
|
||||
src/lib/probe.h \
|
||||
src/lib/probe.c \
|
||||
src/lib/system_stub.h \
|
||||
src/lib/system_stub.c \
|
||||
src/lib/writer.h \
|
||||
src/lib/writer.c \
|
||||
src/lib/util.h \
|
||||
src/lib/util.c \
|
||||
src/lib/bootvar.h \
|
||||
src/lib/bootvar.c
|
||||
|
||||
libcbm_la_CFLAGS = \
|
||||
-D_BOOTMAN_INTERNAL_ \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
libcbm_la_SOURCES = \
|
||||
$(SOURCE_FILES)
|
||||
|
||||
libcbm_la_LIBADD = \
|
||||
src/libnica/libnica.la
|
||||
libcbm_la_CFLAGS = \
|
||||
-D_BOOTMAN_INTERNAL_ \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
clr_boot_manager_SOURCES = \
|
||||
src/cli/cli.h \
|
||||
src/cli/cli.c \
|
||||
src/cli/ops/update.h \
|
||||
src/cli/ops/update.c \
|
||||
src/cli/ops/timeout.h \
|
||||
src/cli/ops/timeout.c \
|
||||
src/cli/ops/report_booted.h \
|
||||
src/cli/ops/report_booted.c \
|
||||
src/cli/main.c
|
||||
libcbm_la_LIBADD = \
|
||||
src/libnica/libnica.la
|
||||
|
||||
clr_boot_manager_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
clr_boot_manager_SOURCES = \
|
||||
src/cli/cli.h \
|
||||
src/cli/cli.c \
|
||||
src/cli/ops/update.h \
|
||||
src/cli/ops/update.c \
|
||||
src/cli/ops/timeout.h \
|
||||
src/cli/ops/timeout.c \
|
||||
src/cli/ops/report_booted.h \
|
||||
src/cli/ops/report_booted.c \
|
||||
src/cli/main.c
|
||||
|
||||
clr_boot_manager_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS)
|
||||
clr_boot_manager_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
clr_boot_manager_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS)
|
||||
|
||||
install-exec-hook:
|
||||
perl ${top_srcdir}/findstatic.pl ${top_builddir}/src/*.o ${top_builddir}/src/*/*.o | grep -v Checking ||:
|
||||
@@ -162,180 +175,196 @@ dist_systemdsystemunit_DATA = ${top_srcdir}/data/clr-boot-manager-booted.service
|
||||
endif
|
||||
|
||||
manpagesdir = $(mandir)/man1
|
||||
manpages_DATA = \
|
||||
man/clr-boot-manager.1
|
||||
manpages_DATA = \
|
||||
man/clr-boot-manager.1
|
||||
|
||||
distclean-local:
|
||||
rm -rf ${top_builddir}/tests/update_playground
|
||||
|
||||
TESTS = \
|
||||
check_core \
|
||||
check_cmdline \
|
||||
check_files \
|
||||
check_legacy \
|
||||
check_os_release \
|
||||
check_uefi \
|
||||
check_grub2 \
|
||||
check_select_bootloader \
|
||||
check_probe
|
||||
TESTS = \
|
||||
check_core \
|
||||
check_cmdline \
|
||||
check_files \
|
||||
check_legacy \
|
||||
check_os_release \
|
||||
check_uefi \
|
||||
check_grub2 \
|
||||
check_select_bootloader \
|
||||
check_probe
|
||||
|
||||
check_PROGRAMS = $(TESTS)
|
||||
|
||||
check_core_SOURCES = \
|
||||
tests/check-core.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
check_core_SOURCES = \
|
||||
tests/check-core.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
|
||||
check_core_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_core_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_core_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_core_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_cmdline_SOURCES = \
|
||||
tests/check-cmdline.c
|
||||
check_cmdline_SOURCES = \
|
||||
tests/check-cmdline.c
|
||||
|
||||
check_cmdline_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_cmdline_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_cmdline_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_cmdline_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_files_SOURCES = \
|
||||
tests/check-files.c \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
check_files_SOURCES = \
|
||||
tests/check-files.c \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
|
||||
check_files_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_files_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_files_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_files_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_legacy_SOURCES = \
|
||||
tests/check-legacy.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
check_legacy_SOURCES = \
|
||||
tests/check-legacy.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
|
||||
check_legacy_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_legacy_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_legacy_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_legacy_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_os_release_SOURCES = \
|
||||
tests/check-os-release.c
|
||||
check_os_release_SOURCES = \
|
||||
tests/check-os-release.c
|
||||
|
||||
check_os_release_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_os_release_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_os_release_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_os_release_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_uefi_SOURCES = \
|
||||
tests/check-uefi.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
check_uefi_SOURCES = \
|
||||
tests/check-uefi.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
|
||||
check_uefi_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_uefi_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_uefi_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_uefi_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_grub2_SOURCES = \
|
||||
tests/check-grub2.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
check_grub2_SOURCES = \
|
||||
tests/check-grub2.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
|
||||
check_grub2_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_grub2_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_grub2_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_grub2_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_select_bootloader_SOURCES = \
|
||||
tests/check-select-bootloader.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
check_select_bootloader_SOURCES = \
|
||||
tests/check-select-bootloader.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
|
||||
check_select_bootloader_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
check_select_bootloader_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_select_bootloader_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_select_bootloader_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
check_probe_SOURCES = \
|
||||
tests/check-probe.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
check_probe_SOURCES = \
|
||||
tests/check-probe.c \
|
||||
tests/blkid-harness.h \
|
||||
tests/system-harness.h \
|
||||
tests/harness.h \
|
||||
tests/harness.c
|
||||
|
||||
check_probe_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_probe_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
check_probe_CFLAGS = \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(CHECK_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
check_probe_LDADD = \
|
||||
libcbm.la \
|
||||
src/libnica/libnica.la \
|
||||
-lefiboot \
|
||||
-lefivar \
|
||||
$(BLKID_LIBS) \
|
||||
$(CHECK_LIBS)
|
||||
|
||||
@VALGRIND_CHECK_RULES@
|
||||
|
||||
|
||||
VALGRIND_SUPPRESSIONS_FILES = \
|
||||
VALGRIND_SUPPRESSIONS_FILES = \
|
||||
${abs_top_srcdir}/sgcheck.suppressions
|
||||
|
||||
+29
-4
@@ -2,6 +2,7 @@ AC_INIT([clr-boot-manager], 1.5.5, [william.douglas@intel.com], [clr-boot-manage
|
||||
AM_INIT_AUTOMAKE([-Wno-portability no-dist-gzip dist-xz foreign subdir-objects])
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_STDC
|
||||
AC_CANONICAL_HOST
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREFIX_DEFAULT(/usr/local)
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -42,7 +43,11 @@ AC_ARG_WITH([bootloader], AS_HELP_STRING([--with-bootloader=BOOTLOADER],
|
||||
if test x$bootloader = "xauto"; then
|
||||
AC_MSG_CHECKING([whether an EFI bootloader is available])
|
||||
if test -e "/usr/lib/systemd/boot/efi"; then
|
||||
bootloader="systemd-boot"
|
||||
if test -e "/usr/lib/shim"; then
|
||||
bootloader="shim-systemd-boot"
|
||||
else
|
||||
bootloader="systemd-boot"
|
||||
fi
|
||||
elif test -e "/usr/lib/goofiboot"; then
|
||||
bootloader="goofiboot"
|
||||
# use newer goofiboot, may be dual installed
|
||||
@@ -50,13 +55,17 @@ if test x$bootloader = "xauto"; then
|
||||
bootloader="gummiboot"
|
||||
else
|
||||
AC_MSG_WARN([Cannot find a valid EFI bootloader, defaulting to systemd-boot])
|
||||
bootloader="systemd-boot"
|
||||
bootloader="shim-systemd-boot"
|
||||
fi
|
||||
AC_MSG_RESULT([$bootloader])
|
||||
fi
|
||||
|
||||
# Now test the option
|
||||
if test x$bootloader = "xsystemd-boot"; then
|
||||
if test x$bootloader = "xshim-systemd-boot"; then
|
||||
have_shim_systemdboot="yes"
|
||||
AC_DEFINE([HAVE_SHIM_SYSTEMD_BOOT], [1], [Using shim-systemd-boot])
|
||||
AC_DEFINE([HAVE_SYSTEMD_BOOT], [1], [Adding systemd-boot])
|
||||
elif test x$bootloader = "xsystemd-boot"; then
|
||||
have_systemdboot="yes"
|
||||
AC_DEFINE([HAVE_SYSTEMD_BOOT], [1], [Using systemd-boot])
|
||||
elif test x$bootloader = "xgummiboot"; then
|
||||
@@ -66,9 +75,10 @@ elif test x$bootloader = "xgoofiboot"; then
|
||||
have_goofiboot="yes"
|
||||
AC_DEFINE([HAVE_GOOFIBOOT], [1], [Using goofiboot])
|
||||
else
|
||||
AC_MSG_ERROR([Unknown bootloader, use: systemd-boot, gummiboot, or goofiboot])
|
||||
AC_MSG_ERROR([Unknown bootloader, use: shim-systemd-boot, systemd-boot, gummiboot, or goofiboot])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([HAVE_SHIM_SYSTEMD_BOOT], [test x$have_shim_systemdboot = "xyes"])
|
||||
AM_CONDITIONAL([HAVE_SYSTEMD_BOOT], [test x$have_systemdboot = "xyes"])
|
||||
AM_CONDITIONAL([HAVE_GUMMIBOOT], [test x$have_gummiboot = "xyes"])
|
||||
AM_CONDITIONAL([HAVE_GOOFIBOOT], [test x$have_goofiboot = "xyes"])
|
||||
@@ -89,6 +99,19 @@ AC_SUBST(kernelmodulesdir)
|
||||
AC_DEFINE_UNQUOTED(KERNEL_MODULES_DIRECTORY, "$kernelmodulesdir",
|
||||
[The location of kernel modules in this OS configuration])
|
||||
|
||||
AC_ARG_WITH([gnu-efi], AS_HELP_STRING([--with-gnu-efi],
|
||||
[the location of gnu-efi headers]), [gnuefi=${withval}],
|
||||
[gnuefi="/usr/include/efi"])
|
||||
AC_SUBST(gnuefi)
|
||||
|
||||
dnl DO NOT use PKG_CHECK_MODULES for efivar: it's headers do not compile with
|
||||
dnl -pendantic --std=c11 with standard -I. Instead capture the directory and use
|
||||
dnl -isystem (to avoid enforcement of the standards).
|
||||
AC_ARG_WITH([efivar], AS_HELP_STRING([--with-efivar],
|
||||
[the location of efivar headers]), [efivar=${withval}],
|
||||
[efivar="/usr/include/efivar"])
|
||||
AC_SUBST(efivar)
|
||||
|
||||
AC_ARG_WITH([kernel-namespace], AS_HELP_STRING([--with-kernel-namespace],
|
||||
[the kernel path namespace to use]), [kernelnamespace=${withval}],
|
||||
[kernelnamespace="org.clearlinux"])
|
||||
@@ -168,6 +191,8 @@ AC_MSG_RESULT([
|
||||
bootloader: ${bootloader}
|
||||
kernel-dir: ${kerneldir}
|
||||
kernel-modules-dir: ${kernelmodulesdir}
|
||||
gnu-efi: ${gnuefi}
|
||||
efivar: ${efivar}
|
||||
kernel-namespace: ${kernelnamespace}
|
||||
kernel-conf-dir: ${kernelconfdir}
|
||||
vendor-kernel-conf-dir: ${vendorkernelconfdir}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
typedef bool (*boot_loader_init)(const BootManager *);
|
||||
typedef bool (*boot_loader_install_kernel)(const BootManager *, const Kernel *);
|
||||
typedef char *(*boot_loader_get_kernel_destination)(const BootManager *);
|
||||
typedef bool (*boot_loader_remove_kernel)(const BootManager *, const Kernel *);
|
||||
typedef bool (*boot_loader_set_default_kernel)(const BootManager *, const Kernel *kernel);
|
||||
typedef bool (*boot_loader_needs_update)(const BootManager *);
|
||||
@@ -43,8 +44,10 @@ typedef enum {
|
||||
* Virtual BootLoader provider
|
||||
*/
|
||||
typedef struct BootLoader {
|
||||
const char *name; /**<Name of the implementation */
|
||||
boot_loader_init init; /**<Init function */
|
||||
const char *name; /**<Name of the implementation */
|
||||
boot_loader_init init; /**<Init function */
|
||||
boot_loader_get_kernel_destination
|
||||
get_kernel_destination; /**<Get location where bootloader expects the kernels to reside */
|
||||
boot_loader_install_kernel install_kernel; /**<Install a given kernel */
|
||||
boot_loader_remove_kernel remove_kernel; /**<Remove a given kernel */
|
||||
boot_loader_set_default_kernel set_default_kernel; /**<Set the default kernel */
|
||||
|
||||
+14
-14
@@ -23,20 +23,20 @@ static bool goofiboot_init(const BootManager *manager)
|
||||
return sd_class_init(manager, &goofiboot_config);
|
||||
}
|
||||
|
||||
__cbm_export__ const BootLoader goofiboot_bootloader = {.name = "goofiboot",
|
||||
.init = goofiboot_init,
|
||||
.install_kernel = sd_class_install_kernel,
|
||||
.remove_kernel = sd_class_remove_kernel,
|
||||
.set_default_kernel =
|
||||
sd_class_set_default_kernel,
|
||||
.needs_install = sd_class_needs_install,
|
||||
.needs_update = sd_class_needs_update,
|
||||
.install = sd_class_install,
|
||||
.update = sd_class_update,
|
||||
.remove = sd_class_remove,
|
||||
.destroy = sd_class_destroy,
|
||||
.get_capabilities =
|
||||
sd_class_get_capabilities };
|
||||
__cbm_export__ const BootLoader
|
||||
goofiboot_bootloader = {.name = "goofiboot",
|
||||
.init = goofiboot_init,
|
||||
.get_kernel_destination = sd_class_get_kernel_destination,
|
||||
.install_kernel = sd_class_install_kernel,
|
||||
.remove_kernel = sd_class_remove_kernel,
|
||||
.set_default_kernel = sd_class_set_default_kernel,
|
||||
.needs_install = sd_class_needs_install,
|
||||
.needs_update = sd_class_needs_update,
|
||||
.install = sd_class_install,
|
||||
.update = sd_class_update,
|
||||
.remove = sd_class_remove,
|
||||
.destroy = sd_class_destroy,
|
||||
.get_capabilities = sd_class_get_capabilities };
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
|
||||
@@ -538,6 +538,10 @@ int grub2_get_capabilities(__cbm_unused__ const BootManager *manager)
|
||||
|
||||
__cbm_export__ const BootLoader grub2_bootloader = {.name = "grub2",
|
||||
.init = grub2_init,
|
||||
.get_kernel_destination = NULL, /* kernel
|
||||
directory
|
||||
only needed for EFI
|
||||
booloaders */
|
||||
.install_kernel = grub2_install_kernel,
|
||||
.remove_kernel = grub2_remove_kernel,
|
||||
.set_default_kernel = grub2_set_default_kernel,
|
||||
|
||||
+14
-14
@@ -23,20 +23,20 @@ static bool gummiboot_init(const BootManager *manager)
|
||||
return sd_class_init(manager, &gummiboot_config);
|
||||
}
|
||||
|
||||
__cbm_export__ const BootLoader gummiboot_bootloader = {.name = "gummiboot",
|
||||
.init = gummiboot_init,
|
||||
.install_kernel = sd_class_install_kernel,
|
||||
.remove_kernel = sd_class_remove_kernel,
|
||||
.set_default_kernel =
|
||||
sd_class_set_default_kernel,
|
||||
.needs_install = sd_class_needs_install,
|
||||
.needs_update = sd_class_needs_update,
|
||||
.install = sd_class_install,
|
||||
.update = sd_class_update,
|
||||
.remove = sd_class_remove,
|
||||
.destroy = sd_class_destroy,
|
||||
.get_capabilities =
|
||||
sd_class_get_capabilities };
|
||||
__cbm_export__ const BootLoader
|
||||
gummiboot_bootloader = {.name = "gummiboot",
|
||||
.init = gummiboot_init,
|
||||
.get_kernel_destination = sd_class_get_kernel_destination,
|
||||
.install_kernel = sd_class_install_kernel,
|
||||
.remove_kernel = sd_class_remove_kernel,
|
||||
.set_default_kernel = sd_class_set_default_kernel,
|
||||
.needs_install = sd_class_needs_install,
|
||||
.needs_update = sd_class_needs_update,
|
||||
.install = sd_class_install,
|
||||
.update = sd_class_update,
|
||||
.remove = sd_class_remove,
|
||||
.destroy = sd_class_destroy,
|
||||
.get_capabilities = sd_class_get_capabilities };
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* This file is part of clr-boot-manager.
|
||||
*
|
||||
* Copyright © 2017 Intel Corporation
|
||||
*
|
||||
* clr-boot-manager is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include "bootloader.h"
|
||||
#include "bootman.h"
|
||||
#include "bootvar.h"
|
||||
#include "config.h"
|
||||
#include "files.h"
|
||||
#include "nica/files.h"
|
||||
#include "systemd-class.h"
|
||||
#include <log.h>
|
||||
|
||||
/*
|
||||
* This file implements 2-stage bootloader configuration in which shim is used as
|
||||
* the first stage bootloader and systemd-boot as the second stage bootloader.
|
||||
*
|
||||
* This implementation uses the following ESP layout:
|
||||
*
|
||||
* /EFI/
|
||||
* Boot/
|
||||
* BOOTX64.EFI <-- this implementation never modifies the
|
||||
* default fallback loader
|
||||
*
|
||||
* /org.clearlinux/
|
||||
* bootloaderx64.efi <-- shim
|
||||
* loaderx64.efi <-- systemd-boot bootloader
|
||||
* mmx64.efi <-- MOK mgr
|
||||
* fbx64.efi <-- MOK mgr
|
||||
*
|
||||
* kernel/ <-- kernels
|
||||
* kernel-org.clearlinux.....
|
||||
* ...
|
||||
*
|
||||
* /loader/ <-- systemd-boot config
|
||||
* entries/ <-- boot menu entries
|
||||
* Clear-linux...conf
|
||||
* ...
|
||||
* loader.conf <-- bootloader config
|
||||
*
|
||||
* Note that default bootloader at /EFI/Boot/BOOTX64.EFI is never modified.
|
||||
* Instead, we create an EFI BootXXX variable and put it first in the BootOrder
|
||||
* EFI variable.
|
||||
*/
|
||||
|
||||
static char *shim_systemd_get_kernel_dst(const BootManager *);
|
||||
static bool shim_systemd_install_kernel(const BootManager *, const Kernel *);
|
||||
static bool shim_systemd_remove_kernel(const BootManager *, const Kernel *);
|
||||
static bool shim_systemd_set_default_kernel(const BootManager *, const Kernel *);
|
||||
static bool shim_systemd_needs_install(const BootManager *);
|
||||
static bool shim_systemd_needs_update(const BootManager *);
|
||||
static bool shim_systemd_install(const BootManager *);
|
||||
static bool shim_systemd_update(const BootManager *);
|
||||
static bool shim_systemd_remove(const BootManager *);
|
||||
static bool shim_systemd_init(const BootManager *);
|
||||
static void shim_systemd_destroy(const BootManager *);
|
||||
static int shim_systemd_get_capabilities(const BootManager *);
|
||||
|
||||
__cbm_export__ const BootLoader
|
||||
shim_systemd_bootloader = {.name = "systemd",
|
||||
.init = shim_systemd_init,
|
||||
.get_kernel_destination = shim_systemd_get_kernel_dst,
|
||||
.install_kernel = shim_systemd_install_kernel,
|
||||
.remove_kernel = shim_systemd_remove_kernel,
|
||||
.set_default_kernel = shim_systemd_set_default_kernel,
|
||||
.needs_install = shim_systemd_needs_install,
|
||||
.needs_update = shim_systemd_needs_update,
|
||||
.install = shim_systemd_install,
|
||||
.update = shim_systemd_update,
|
||||
.remove = shim_systemd_remove,
|
||||
.destroy = shim_systemd_destroy,
|
||||
.get_capabilities = shim_systemd_get_capabilities };
|
||||
|
||||
#if UINTPTR_MAX == 0xffffffffffffffff
|
||||
#define EFI_SUFFIX "x64.efi"
|
||||
#else
|
||||
#define EFI_SUFFIX "ia32.efi"
|
||||
#endif
|
||||
|
||||
/* Layout entries, see the layout description at the top of the file. */
|
||||
#define SHIM_SRC_DIR "usr/lib/shim"
|
||||
#define SHIM_SRC \
|
||||
SHIM_SRC_DIR \
|
||||
"/" \
|
||||
"shim" EFI_SUFFIX
|
||||
#define MM_SRC \
|
||||
SHIM_SRC_DIR \
|
||||
"/" \
|
||||
"mm" EFI_SUFFIX
|
||||
#define FB_SRC \
|
||||
SHIM_SRC_DIR \
|
||||
"/" \
|
||||
"fb" EFI_SUFFIX
|
||||
#define SYSTEMD_SRC_DIR "usr/lib/systemd/boot/efi"
|
||||
#define SYSTEMD_SRC \
|
||||
SYSTEMD_SRC_DIR \
|
||||
"/" \
|
||||
"systemd-boot" EFI_SUFFIX
|
||||
#define DST_DIR "/" KERNEL_NAMESPACE
|
||||
#define SHIM_DST \
|
||||
DST_DIR \
|
||||
"/" \
|
||||
"bootloader" EFI_SUFFIX
|
||||
#define SYSTEMD_DST \
|
||||
DST_DIR \
|
||||
"/" \
|
||||
"loader" EFI_SUFFIX
|
||||
#define KERNEL_DST_DIR DST_DIR "/kernel"
|
||||
#define SYSTEMD_CONFIG_DIR "/loader"
|
||||
#define SYSTEMD_CONFIG SYSTEMD_CONFIG_DIR "/loader.conf"
|
||||
#define SYSTEMD_ENTRIES SYSTEMD_CONFIG_DIR "/entries"
|
||||
|
||||
static char *shim_src;
|
||||
static char *shim_dst_host; /* as accessible by the CMB for file ops. */
|
||||
static char *shim_dst_esp; /* absolute location of shim on the ESP. */
|
||||
static char *systemd_src;
|
||||
static char *systemd_dst_host;
|
||||
|
||||
extern void sd_class_set_get_kernel_destination_impl(char *(*)(const BootManager *));
|
||||
|
||||
static char *shim_systemd_get_kernel_dst(__cbm_unused__ const BootManager *manager)
|
||||
{
|
||||
return strdup(KERNEL_DST_DIR);
|
||||
}
|
||||
|
||||
static bool shim_systemd_install_kernel(const BootManager *manager, const Kernel *kernel)
|
||||
{
|
||||
return sd_class_install_kernel(manager, kernel);
|
||||
}
|
||||
|
||||
static bool shim_systemd_remove_kernel(const BootManager *manager, const Kernel *kernel)
|
||||
{
|
||||
return sd_class_remove_kernel(manager, kernel);
|
||||
}
|
||||
|
||||
static bool shim_systemd_set_default_kernel(const BootManager *manager, const Kernel *kernel)
|
||||
{
|
||||
/* this writes systemd config. systemd has the configuration paths
|
||||
* hardcoded, hence whatever sd_class is doing is OK. */
|
||||
return sd_class_set_default_kernel(manager, kernel);
|
||||
}
|
||||
|
||||
static bool exists_identical(const char *path, const char *spath)
|
||||
{
|
||||
if (!nc_file_exists(path))
|
||||
return false;
|
||||
if (spath && !cbm_files_match(path, spath))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool shim_systemd_needs_install(const BootManager *manager)
|
||||
{
|
||||
(void)manager;
|
||||
if (!exists_identical(shim_dst_host, NULL))
|
||||
return true;
|
||||
if (!exists_identical(systemd_dst_host, NULL))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool shim_systemd_needs_update(const BootManager *manager)
|
||||
{
|
||||
(void)manager;
|
||||
if (!exists_identical(shim_dst_host, shim_src))
|
||||
return true;
|
||||
if (!exists_identical(systemd_dst_host, systemd_src))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool make_layout(const BootManager *manager)
|
||||
{
|
||||
char *boot_root = boot_manager_get_boot_dir((BootManager *)manager);
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, PATH_MAX, "%s%s", boot_root, DST_DIR);
|
||||
if (!nc_mkdir_p(path, 00755)) {
|
||||
goto fail;
|
||||
}
|
||||
snprintf(path, PATH_MAX, "%s%s", boot_root, KERNEL_DST_DIR);
|
||||
if (!nc_mkdir_p(path, 00755)) {
|
||||
goto fail;
|
||||
}
|
||||
snprintf(path, PATH_MAX, "%s%s", boot_root, SYSTEMD_ENTRIES);
|
||||
if (!nc_mkdir_p(path, 00755)) {
|
||||
goto fail;
|
||||
}
|
||||
return true;
|
||||
fail:
|
||||
LOG_FATAL("Failed to make dir: %s", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool shim_systemd_install(const BootManager *manager)
|
||||
{
|
||||
char varname[9];
|
||||
|
||||
if (!make_layout(manager)) {
|
||||
LOG_FATAL("Cannot create layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!copy_file_atomic(shim_src, shim_dst_host, 00644)) {
|
||||
LOG_FATAL("Cannot copy %s to %s", shim_src, shim_dst_host);
|
||||
return false;
|
||||
}
|
||||
if (!copy_file_atomic(systemd_src, systemd_dst_host, 00644)) {
|
||||
LOG_FATAL("Cannot copy %s to %s", systemd_src, systemd_dst_host);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bootvar_create(BOOT_DIRECTORY, shim_dst_esp, varname, 9)) {
|
||||
LOG_FATAL("Cannot create EFI variable");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool shim_systemd_update(const BootManager *manager)
|
||||
{
|
||||
return shim_systemd_install(manager);
|
||||
}
|
||||
|
||||
static bool shim_systemd_remove(const BootManager *manager)
|
||||
{
|
||||
(void)manager;
|
||||
fprintf(stderr, "%s is not implemented\n", __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool shim_systemd_init(const BootManager *manager)
|
||||
{
|
||||
size_t len;
|
||||
char *prefix, *boot_root;
|
||||
|
||||
if (bootvar_init())
|
||||
return false;
|
||||
|
||||
/* init systemd-class since we're reusing it for kernel install.
|
||||
* specific values do not matter as long as sd_class is not used to
|
||||
* install the bootloaders themselves. */
|
||||
static BootLoaderConfig systemd_config = {.vendor_dir = "systemd",
|
||||
.efi_dir = "/usr/lib/systemd/boot/efi",
|
||||
.efi_blob = "systemd-boot" EFI_SUFFIX,
|
||||
.name = "systemd-boot" };
|
||||
sd_class_init(manager, &systemd_config);
|
||||
sd_class_set_get_kernel_destination_impl(shim_systemd_get_kernel_dst);
|
||||
|
||||
prefix = strdup(boot_manager_get_prefix((BootManager *)manager));
|
||||
len = strlen(prefix);
|
||||
if (len > 0 && prefix[len - 1] == '/')
|
||||
prefix[len - 1] = '\0';
|
||||
shim_src = string_printf("%s/%s", prefix, SHIM_SRC);
|
||||
systemd_src = string_printf("%s/%s", prefix, SYSTEMD_SRC);
|
||||
|
||||
boot_root = strdup(boot_manager_get_boot_dir((BootManager *)manager));
|
||||
len = strlen(boot_root);
|
||||
/* SHIM_DST and SYSTEMD_DST are defined with leading '/', take extra
|
||||
* care to produce clean paths. */
|
||||
if (len > 0 && boot_root[len - 1] == '/')
|
||||
boot_root[len - 1] = '\0';
|
||||
shim_dst_host = string_printf("%s%s", boot_root, SHIM_DST);
|
||||
systemd_dst_host = string_printf("%s%s", boot_root, SYSTEMD_DST);
|
||||
|
||||
shim_dst_esp = SHIM_DST;
|
||||
|
||||
free(prefix);
|
||||
free(boot_root);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void shim_systemd_destroy(const BootManager *manager)
|
||||
{
|
||||
(void)manager;
|
||||
|
||||
free(shim_src);
|
||||
free(systemd_src);
|
||||
free(shim_dst_host);
|
||||
free(systemd_dst_host);
|
||||
bootvar_destroy();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int shim_systemd_get_capabilities(const BootManager *manager)
|
||||
{
|
||||
(void)manager;
|
||||
return BOOTLOADER_CAP_GPT | BOOTLOADER_CAP_UEFI;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -38,11 +38,14 @@ typedef struct SdClassConfig {
|
||||
char *efi_blob_dest;
|
||||
char *default_path_efi_blob;
|
||||
char *loader_config;
|
||||
char *kernel_dir;
|
||||
} SdClassConfig;
|
||||
|
||||
static SdClassConfig sd_class_config = { 0 };
|
||||
static BootLoaderConfig *sd_config = NULL;
|
||||
|
||||
static char *(*get_kernel_destination_impl)(const BootManager *);
|
||||
|
||||
#define FREE_IF_SET(x) \
|
||||
{ \
|
||||
if (x) { \
|
||||
@@ -65,6 +68,8 @@ bool sd_class_init(const BootManager *manager, BootLoaderConfig *config)
|
||||
|
||||
sd_config = config;
|
||||
|
||||
get_kernel_destination_impl = sd_class_get_kernel_destination;
|
||||
|
||||
/* Cache all of these to save useless allocs of the same paths later */
|
||||
base_path = boot_manager_get_boot_dir((BootManager *)manager);
|
||||
OOM_CHECK_RET(base_path, false);
|
||||
@@ -112,9 +117,16 @@ bool sd_class_init(const BootManager *manager, BootLoaderConfig *config)
|
||||
OOM_CHECK_RET(loader_config, false);
|
||||
sd_class_config.loader_config = loader_config;
|
||||
|
||||
sd_class_config.kernel_dir = "/EFI/" KERNEL_NAMESPACE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sd_class_set_get_kernel_destination_impl(char *(*impl)(const BootManager *))
|
||||
{
|
||||
get_kernel_destination_impl = impl;
|
||||
}
|
||||
|
||||
void sd_class_destroy(__cbm_unused__ const BootManager *manager)
|
||||
{
|
||||
FREE_IF_SET(sd_class_config.efi_dir);
|
||||
@@ -151,7 +163,7 @@ static char *get_entry_path_for_kernel(BootManager *manager, const Kernel *kerne
|
||||
NULL);
|
||||
}
|
||||
|
||||
static bool sd_class_ensure_dirs(__cbm_unused__ const BootManager *manager)
|
||||
static bool sd_class_ensure_dirs(void)
|
||||
{
|
||||
if (!nc_mkdir_p(sd_class_config.efi_dir, 00755)) {
|
||||
LOG_FATAL("Failed to create %s: %s", sd_class_config.efi_dir, strerror(errno));
|
||||
@@ -174,6 +186,11 @@ static bool sd_class_ensure_dirs(__cbm_unused__ const BootManager *manager)
|
||||
return true;
|
||||
}
|
||||
|
||||
char *sd_class_get_kernel_destination(__cbm_unused__ const BootManager *manager)
|
||||
{
|
||||
return strdup(sd_class_config.kernel_dir);
|
||||
}
|
||||
|
||||
bool sd_class_install_kernel(const BootManager *manager, const Kernel *kernel)
|
||||
{
|
||||
if (!manager || !kernel) {
|
||||
@@ -187,12 +204,6 @@ bool sd_class_install_kernel(const BootManager *manager, const Kernel *kernel)
|
||||
|
||||
conf_path = get_entry_path_for_kernel((BootManager *)manager, kernel);
|
||||
|
||||
/* Ensure all the relevant directories exist */
|
||||
if (!sd_class_ensure_dirs(manager)) {
|
||||
LOG_FATAL("Failed to create required directories");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cbm_writer_open(writer)) {
|
||||
DECLARE_OOM();
|
||||
abort();
|
||||
@@ -210,14 +221,14 @@ bool sd_class_install_kernel(const BootManager *manager, const Kernel *kernel)
|
||||
/* Standard title + linux lines */
|
||||
cbm_writer_append_printf(writer, "title %s\n", os_name);
|
||||
cbm_writer_append_printf(writer,
|
||||
"linux /EFI/%s/%s\n",
|
||||
KERNEL_NAMESPACE,
|
||||
"linux %s/%s\n",
|
||||
get_kernel_destination_impl(manager),
|
||||
kernel->target.path);
|
||||
/* Optional initrd */
|
||||
if (kernel->target.initrd_path) {
|
||||
cbm_writer_append_printf(writer,
|
||||
"initrd /EFI/%s/%s\n",
|
||||
KERNEL_NAMESPACE,
|
||||
"initrd %s/%s\n",
|
||||
get_kernel_destination_impl(manager),
|
||||
kernel->target.initrd_path);
|
||||
}
|
||||
/* Add the root= section */
|
||||
@@ -290,11 +301,6 @@ bool sd_class_set_default_kernel(const BootManager *manager, const Kernel *kerne
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sd_class_ensure_dirs(manager)) {
|
||||
LOG_FATAL("Failed to create required directories for %s", sd_config->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
autofree(char) *item_name = NULL;
|
||||
int timeout = 0;
|
||||
const char *prefix = NULL;
|
||||
@@ -404,7 +410,7 @@ bool sd_class_install(const BootManager *manager)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sd_class_ensure_dirs(manager)) {
|
||||
if (!sd_class_ensure_dirs()) {
|
||||
LOG_FATAL("Failed to create required directories for %s", sd_config->name);
|
||||
return false;
|
||||
}
|
||||
@@ -439,7 +445,7 @@ bool sd_class_update(const BootManager *manager)
|
||||
if (!manager) {
|
||||
return false;
|
||||
}
|
||||
if (!sd_class_ensure_dirs(manager)) {
|
||||
if (!sd_class_ensure_dirs()) {
|
||||
LOG_FATAL("Failed to create required directories for %s", sd_config->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ typedef struct BootLoaderConfig {
|
||||
const char *name;
|
||||
} BootLoaderConfig;
|
||||
|
||||
char *sd_class_get_kernel_destination(const BootManager *manager);
|
||||
|
||||
bool sd_class_install_kernel(const BootManager *manager, const Kernel *kernel);
|
||||
|
||||
bool sd_class_remove_kernel(const BootManager *manager, const Kernel *kernel);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
* Total "usable" bootloaders
|
||||
*/
|
||||
extern const BootLoader grub2_bootloader;
|
||||
extern const BootLoader shim_systemd_bootloader;
|
||||
extern const BootLoader systemd_bootloader;
|
||||
extern const BootLoader gummiboot_bootloader;
|
||||
extern const BootLoader goofiboot_bootloader;
|
||||
@@ -41,7 +42,9 @@ extern const BootLoader syslinux_bootloader;
|
||||
*/
|
||||
const BootLoader *bootman_known_loaders[] =
|
||||
{ &grub2_bootloader, /**<Always place first to allow syslinux to override */
|
||||
#if defined(HAVE_SYSTEMD_BOOT)
|
||||
#if defined(HAVE_SHIM_SYSTEMD_BOOT)
|
||||
&shim_systemd_bootloader,
|
||||
#elif defined(HAVE_SYSTEMD_BOOT)
|
||||
&systemd_bootloader,
|
||||
#elif defined(HAVE_GUMMIBOOT)
|
||||
&gummiboot_bootloader,
|
||||
|
||||
+30
-43
@@ -592,36 +592,26 @@ bool boot_manager_install_kernel_internal(const BootManager *manager, const Kern
|
||||
autofree(char) *base_path = NULL;
|
||||
autofree(char) *initrd_target = NULL;
|
||||
const char *initrd_source = NULL;
|
||||
bool is_uefi = false;
|
||||
autofree(char) *efi_boot_dir = NULL;
|
||||
int is_uefi = (manager->bootloader->get_capabilities(manager) & BOOTLOADER_CAP_UEFI);
|
||||
autofree(char) *efi_boot_dir =
|
||||
is_uefi ? manager->bootloader->get_kernel_destination(manager) : NULL;
|
||||
|
||||
assert(manager != NULL);
|
||||
assert(kernel != NULL);
|
||||
|
||||
if (is_uefi && !efi_boot_dir)
|
||||
return false;
|
||||
|
||||
/* Boot path */
|
||||
base_path = boot_manager_get_boot_dir((BootManager *)manager);
|
||||
OOM_CHECK_RET(base_path, false);
|
||||
|
||||
/* Determine if UEFI is in use */
|
||||
if ((manager->bootloader->get_capabilities(manager) & BOOTLOADER_CAP_UEFI) ==
|
||||
BOOTLOADER_CAP_UEFI) {
|
||||
is_uefi = true;
|
||||
efi_boot_dir = nc_build_case_correct_path(base_path, "EFI", KERNEL_NAMESPACE, NULL);
|
||||
}
|
||||
|
||||
/* For UEFI kernels we namespace into /EFI/$NEEDLE, i.e. /EFI/org.clearlinux */
|
||||
if (is_uefi) {
|
||||
/* Ensure namespace directory exists */
|
||||
if (!nc_mkdir_p(efi_boot_dir, 00755)) {
|
||||
LOG_FATAL("Failed to create namespace directory: %s %s",
|
||||
efi_boot_dir,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
kfile_target = string_printf("%s/%s", efi_boot_dir, kernel->target.path);
|
||||
} else {
|
||||
kfile_target = string_printf("%s/%s", base_path, kernel->target.legacy_path);
|
||||
}
|
||||
/* for UEFI, the kernel location is prefixed with efi_boot_dir which is
|
||||
* guaranteed to start with '/' since it's its absolute path on ESP. */
|
||||
kfile_target = string_printf("%s%s/%s",
|
||||
base_path,
|
||||
(is_uefi ? efi_boot_dir : ""),
|
||||
(is_uefi ? kernel->target.path : kernel->target.legacy_path));
|
||||
|
||||
/* Now copy the kernel file to it's new location */
|
||||
if (!cbm_files_match(kernel->source.path, kfile_target)) {
|
||||
@@ -641,11 +631,10 @@ bool boot_manager_install_kernel_internal(const BootManager *manager, const Kern
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_uefi) {
|
||||
initrd_target = string_printf("%s/%s", efi_boot_dir, kernel->target.initrd_path);
|
||||
} else {
|
||||
initrd_target = string_printf("%s/%s", base_path, kernel->target.initrd_path);
|
||||
}
|
||||
initrd_target = string_printf("%s%s/%s",
|
||||
base_path,
|
||||
(is_uefi ? efi_boot_dir : ""),
|
||||
kernel->target.initrd_path);
|
||||
|
||||
if (!cbm_files_match(initrd_source, initrd_target)) {
|
||||
if (!copy_file_atomic(initrd_source, initrd_target, 00644)) {
|
||||
@@ -676,33 +665,31 @@ bool boot_manager_remove_kernel_internal(const BootManager *manager, const Kerne
|
||||
autofree(char) *kfile_target = NULL;
|
||||
autofree(char) *base_path = NULL;
|
||||
autofree(char) *initrd_target = NULL;
|
||||
bool is_uefi = false;
|
||||
autofree(char) *efi_boot_dir = NULL;
|
||||
int is_uefi = (manager->bootloader->get_capabilities(manager) & BOOTLOADER_CAP_UEFI);
|
||||
autofree(char) *efi_boot_dir =
|
||||
is_uefi ? manager->bootloader->get_kernel_destination(manager) : NULL;
|
||||
|
||||
assert(manager != NULL);
|
||||
assert(kernel != NULL);
|
||||
|
||||
/* if it's UEFI, then bootloader->get_kernel_dst() must return a value. */
|
||||
if (is_uefi && !efi_boot_dir)
|
||||
return false;
|
||||
|
||||
/* Boot path */
|
||||
base_path = boot_manager_get_boot_dir((BootManager *)manager);
|
||||
OOM_CHECK_RET(base_path, false);
|
||||
|
||||
/* Determine if UEFI is in use */
|
||||
if ((manager->bootloader->get_capabilities(manager) & BOOTLOADER_CAP_UEFI) ==
|
||||
BOOTLOADER_CAP_UEFI) {
|
||||
is_uefi = true;
|
||||
efi_boot_dir = nc_build_case_correct_path(base_path, "EFI", KERNEL_NAMESPACE, NULL);
|
||||
}
|
||||
|
||||
/* Remove old blobs */
|
||||
if (is_uefi) {
|
||||
kfile_target = string_printf("%s/%s", efi_boot_dir, kernel->target.path);
|
||||
} else {
|
||||
kfile_target = string_printf("%s/%s", base_path, kernel->target.legacy_path);
|
||||
}
|
||||
kfile_target = string_printf("%s%s/%s",
|
||||
base_path,
|
||||
(is_uefi ? efi_boot_dir : ""),
|
||||
(is_uefi ? kernel->target.path : kernel->target.legacy_path));
|
||||
|
||||
if (kernel->source.initrd_file) {
|
||||
initrd_target = string_printf("%s/%s",
|
||||
is_uefi ? efi_boot_dir : base_path,
|
||||
initrd_target = string_printf("%s%s/%s",
|
||||
base_path,
|
||||
(is_uefi ? efi_boot_dir : ""),
|
||||
kernel->target.initrd_path);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* This file is part of clr-boot-manager.
|
||||
*
|
||||
* Copyright © 2017 Intel Corporation
|
||||
*
|
||||
* clr-boot-manager is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "bootvar.h"
|
||||
|
||||
#include <endian.h>
|
||||
/* Workaround for using --std=c11 in CBM. Provide "relaxed" defines which efivar
|
||||
* expects. */
|
||||
#define BYTE_ORDER __BYTE_ORDER
|
||||
#define LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||
#define BIG_ENDIAN __BIG_ENDIAN
|
||||
|
||||
#include <alloca.h>
|
||||
#include <blkid.h>
|
||||
#include <ctype.h>
|
||||
#include <efi.h>
|
||||
#include <efiboot.h>
|
||||
#include <efilib.h>
|
||||
#include <efivar.h>
|
||||
#include <errno.h>
|
||||
#include <log.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
/* 1K is the limit for boot var storage that efivar defines. it should be
|
||||
* enough. actual space occupied is normally >2 times less. */
|
||||
#define BOOT_VAR_MAX 1024
|
||||
|
||||
/* env var to turn on the test mode. if set to "yes", turns off any side-effects
|
||||
* functions defined in this file may have: the call will always succeed without
|
||||
* side effects. */
|
||||
#define CBM_BOOTVAR_TEST_MODE_VAR "CBM_BOOTVAR_TEST_MODE"
|
||||
|
||||
typedef struct boot_rec boot_rec_t;
|
||||
|
||||
struct boot_rec {
|
||||
char *name;
|
||||
int num;
|
||||
unsigned char *data;
|
||||
boot_rec_t *next;
|
||||
};
|
||||
|
||||
static boot_rec_t *boot_recs;
|
||||
static int boot_recs_cnt;
|
||||
|
||||
static int test_mode = 0;
|
||||
|
||||
static void bootvar_free_boot_recs(void)
|
||||
{
|
||||
boot_rec_t *p, *c;
|
||||
c = boot_recs;
|
||||
if (!c)
|
||||
return;
|
||||
boot_recs = NULL;
|
||||
do {
|
||||
p = c;
|
||||
c = c->next;
|
||||
free(p);
|
||||
} while (c);
|
||||
}
|
||||
|
||||
static void bootvar_print_boot_recs(void) __attribute__((unused));
|
||||
static void bootvar_print_boot_recs(void)
|
||||
{
|
||||
boot_rec_t *c = boot_recs;
|
||||
if (!c)
|
||||
return;
|
||||
do {
|
||||
fprintf(stderr, "Boot record #%d: %s\n", c->num, c->name);
|
||||
} while ((c = c->next));
|
||||
}
|
||||
|
||||
/* enumerates boot recs and initializes boot_recs and boot_recs_cnt. */
|
||||
static int bootvar_read_boot_recs(void)
|
||||
{
|
||||
int res;
|
||||
efi_guid_t *guid = NULL;
|
||||
char *name = NULL;
|
||||
boot_rec_t *p = NULL, *c;
|
||||
int i = 0;
|
||||
|
||||
bootvar_free_boot_recs();
|
||||
|
||||
while ((res = efi_get_next_variable_name(&guid, &name)) > 0) {
|
||||
char *num_end;
|
||||
if (strncmp(name, "Boot", 4))
|
||||
continue;
|
||||
if (!isxdigit(name[4]) || !isxdigit(name[5]) || !isxdigit(name[6]) ||
|
||||
!isxdigit(name[7]))
|
||||
continue;
|
||||
if (memcmp(guid, &efi_guid_global, sizeof(efi_guid_t)))
|
||||
continue;
|
||||
|
||||
c = (boot_rec_t *)malloc(sizeof(boot_rec_t));
|
||||
memset(c, 0, sizeof(boot_rec_t));
|
||||
c->name = strdup(name);
|
||||
c->num = (int)strtol(name + 4, &num_end, 16);
|
||||
if (num_end - name - 4 != 4)
|
||||
continue;
|
||||
|
||||
if (!boot_recs) {
|
||||
boot_recs = p = c;
|
||||
} else {
|
||||
p->next = c;
|
||||
p = c;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (res < 0) {
|
||||
LOG_FATAL("efi_get_next_variable_name() failed: %s", strerror(errno));
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
boot_recs_cnt = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* given the record, puts it first in the boot order (via BootOrder EFI
|
||||
* variable). */
|
||||
static int bootvar_push_to_boot_order(boot_rec_t *rec)
|
||||
{
|
||||
uint16_t number;
|
||||
uint16_t *boot_order;
|
||||
uint16_t *new_boot_order;
|
||||
size_t boot_order_size;
|
||||
size_t new_boot_order_size;
|
||||
uint32_t boot_order_attrs;
|
||||
unsigned int i;
|
||||
int found = 0;
|
||||
|
||||
if (!rec || !rec->name)
|
||||
return -EBOOT_VAR_ERR;
|
||||
|
||||
if (efi_get_variable(EFI_GLOBAL_GUID,
|
||||
"BootOrder",
|
||||
(uint8_t **)&boot_order,
|
||||
&boot_order_size,
|
||||
&boot_order_attrs)) {
|
||||
LOG_FATAL("efi_get_variable() failed: %s", strerror(errno));
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
sscanf(rec->name, "Boot%04hX", &number);
|
||||
|
||||
/* read as uint16_t, hence twice less the returned size */
|
||||
boot_order_size >>= 1;
|
||||
|
||||
for (i = 0; i < boot_order_size; i++) {
|
||||
if (boot_order[i] == number) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
new_boot_order_size = boot_order_size + 1;
|
||||
new_boot_order = (uint16_t *)malloc(new_boot_order_size * sizeof(uint16_t));
|
||||
new_boot_order[0] = number;
|
||||
memcpy(new_boot_order + 1, boot_order, boot_order_size * sizeof(uint16_t));
|
||||
} else {
|
||||
uint16_t *c;
|
||||
new_boot_order = (uint16_t *)malloc(boot_order_size * sizeof(uint16_t));
|
||||
new_boot_order[0] = number;
|
||||
c = new_boot_order + 1;
|
||||
for (i = 0; i < boot_order_size; i++) {
|
||||
if (boot_order[i] != number) {
|
||||
*c = boot_order[i];
|
||||
c++;
|
||||
}
|
||||
}
|
||||
new_boot_order_size = (size_t)(c - new_boot_order);
|
||||
}
|
||||
|
||||
new_boot_order_size <<= 1;
|
||||
if (efi_set_variable(EFI_GLOBAL_GUID,
|
||||
"BootOrder",
|
||||
(uint8_t *)new_boot_order,
|
||||
new_boot_order_size,
|
||||
boot_order_attrs,
|
||||
0644)) {
|
||||
LOG_FATAL("efi_set_variable() failed: %s", strerror(errno));
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp(const void *a, const void *b)
|
||||
{
|
||||
return *((int *)a) - *((int *)b);
|
||||
}
|
||||
|
||||
/* finds the first available free number for a boot var. */
|
||||
static int bootvar_find_free_no(void)
|
||||
{
|
||||
int *nums;
|
||||
int res;
|
||||
int i = 0;
|
||||
boot_rec_t *c = boot_recs;
|
||||
size_t cnt;
|
||||
|
||||
if (!boot_recs)
|
||||
return -1;
|
||||
if (!boot_recs_cnt)
|
||||
return 0; /* no records. */
|
||||
|
||||
cnt = (size_t)boot_recs_cnt;
|
||||
|
||||
nums = (int *)alloca(sizeof(int) * cnt);
|
||||
memset(nums, 0, sizeof(int) * cnt);
|
||||
|
||||
do {
|
||||
nums[i] = c->num;
|
||||
i++;
|
||||
} while ((c = c->next));
|
||||
|
||||
qsort(nums, cnt, sizeof(int), cmp);
|
||||
|
||||
for (i = 0, res = 0; i < boot_recs_cnt; i++, res++) {
|
||||
if (res < nums[i])
|
||||
break;
|
||||
}
|
||||
if (res == nums[boot_recs_cnt - 1])
|
||||
res++; /* no gap. */
|
||||
return res;
|
||||
}
|
||||
|
||||
/* finds and returns boot rec whose value is data of size. NULL if not found. */
|
||||
static boot_rec_t *bootvar_find_boot_rec(uint8_t *data, size_t size)
|
||||
{
|
||||
boot_rec_t *c = boot_recs;
|
||||
boot_rec_t *res = NULL;
|
||||
|
||||
uint8_t *cdata;
|
||||
size_t csize;
|
||||
uint32_t cattr;
|
||||
|
||||
if (!boot_recs || !boot_recs_cnt)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
if (efi_get_variable(EFI_GLOBAL_GUID, c->name, &cdata, &csize, &cattr) < 0) {
|
||||
LOG_ERROR("efi_get_variable() failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (csize == size && !memcmp(cdata, data, csize)) {
|
||||
res = c;
|
||||
break;
|
||||
}
|
||||
} while ((c = c->next));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef struct part_info {
|
||||
char disk_path[PATH_MAX];
|
||||
int part_no;
|
||||
char part_type[36 + 1]; /* GUID string, hyphen notation */
|
||||
} part_info_t;
|
||||
|
||||
/* given the location of the ESP mount point, returns the partition information
|
||||
* needed to create boot variable which points to that bootloader. */
|
||||
static int bootvar_get_part_info(const char *path, part_info_t *pi)
|
||||
{
|
||||
blkid_probe probe;
|
||||
blkid_partition part;
|
||||
blkid_partlist parts;
|
||||
struct stat st;
|
||||
dev_t disk_dev;
|
||||
char disk_path[PATH_MAX];
|
||||
const char *part_type;
|
||||
|
||||
if (stat(path, &st)) {
|
||||
LOG_FATAL("stat() failed on %s: %s", path, strerror(errno));
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
strcpy(disk_path, "/dev/");
|
||||
if (blkid_devno_to_wholedisk(st.st_dev, disk_path + 5, PATH_MAX - 5, &disk_dev)) {
|
||||
LOG_FATAL("blkid_devno_to_wholedisk() error");
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
if (!(probe = blkid_new_probe_from_filename(disk_path))) {
|
||||
LOG_FATAL("blkid_new_probe_from_filename() error");
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
if (blkid_probe_enable_partitions(probe, 1)) {
|
||||
LOG_FATAL("blkid_probe_enable_partitions() error");
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
if (!(parts = blkid_probe_get_partitions(probe))) {
|
||||
LOG_FATAL("blkid_probe_get_partitions() error");
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
if (!(part = blkid_partlist_devno_to_partition(parts, st.st_dev))) {
|
||||
LOG_FATAL("blkid_partlist_devno_to_partition() error");
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
if ((pi->part_no = blkid_partition_get_partno(part)) < 0) {
|
||||
LOG_FATAL("blkid_partition_get_partno() error");
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
part_type = blkid_partition_get_type_string(part);
|
||||
if (!part_type) {
|
||||
LOG_FATAL("blkid_partition_get_type_string() returned NULL");
|
||||
return -EBOOT_VAR_ERR;
|
||||
} else if (strlen(part_type) != 36) {
|
||||
LOG_FATAL("partition type does not seem to be a GUID: %s", part_type);
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
snprintf(pi->disk_path, strlen(disk_path) + 1, "%s", disk_path);
|
||||
snprintf(pi->part_type, 36 + 1, "%s", part_type);
|
||||
|
||||
blkid_free_probe(probe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* attempts to look up existing record, otherwise creates a new one. */
|
||||
static boot_rec_t *bootvar_add_boot_rec(uint8_t *data, size_t len)
|
||||
{
|
||||
char name[9]; /* variable name, e.g. "BootXXXX". */
|
||||
int slot;
|
||||
uint32_t attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
EFI_VARIABLE_RUNTIME_ACCESS;
|
||||
boot_rec_t *c, *res = bootvar_find_boot_rec(data, len);
|
||||
|
||||
if (res)
|
||||
return res;
|
||||
/* no such record, create one. */
|
||||
slot = bootvar_find_free_no();
|
||||
if (slot < 0)
|
||||
return NULL;
|
||||
if (snprintf(name, 9, "Boot%04X", slot) > 8)
|
||||
return NULL;
|
||||
if (efi_set_variable(EFI_GLOBAL_GUID, name, data, len, attr, 0644) < 0) {
|
||||
LOG_FATAL("efi_set_variable() failed: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
/* re-read the records and find the variable that was just created. */
|
||||
if (bootvar_read_boot_recs() < 0)
|
||||
return NULL;
|
||||
if (!boot_recs)
|
||||
return NULL; /* something went terribly wrong. */
|
||||
c = boot_recs;
|
||||
do {
|
||||
if (!strcmp(c->name, name)) {
|
||||
res = c;
|
||||
break;
|
||||
}
|
||||
} while ((c = c->next));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int bootvar_create(const char *esp_mount_path, const char *bootloader_esp_path, char *varname,
|
||||
size_t size)
|
||||
{
|
||||
part_info_t pi;
|
||||
uint8_t fdev_path[PATH_MAX];
|
||||
uint8_t data[BOOT_VAR_MAX]; /* this is what efivar supports and it should be
|
||||
enough. */
|
||||
long int len;
|
||||
boot_rec_t *rec;
|
||||
|
||||
if (test_mode)
|
||||
return 0;
|
||||
|
||||
if (bootvar_get_part_info(esp_mount_path, &pi))
|
||||
return -1;
|
||||
|
||||
len = efi_generate_file_device_path_from_esp(fdev_path,
|
||||
PATH_MAX,
|
||||
pi.disk_path,
|
||||
pi.part_no,
|
||||
bootloader_esp_path,
|
||||
EFIBOOT_ABBREV_HD);
|
||||
if (len < 0) {
|
||||
LOG_FATAL("efi_generate_file_device_path_from_esp() failed: %s", strerror(errno));
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
len = efi_loadopt_create(data,
|
||||
BOOT_VAR_MAX,
|
||||
LOAD_OPTION_ACTIVE,
|
||||
(void *)fdev_path,
|
||||
len,
|
||||
(unsigned char *)"Linux bootloader",
|
||||
NULL,
|
||||
0);
|
||||
if (len < 0) {
|
||||
LOG_FATAL("efi_loadopt_create() failed: %s", strerror(errno));
|
||||
return -EBOOT_VAR_ERR;
|
||||
}
|
||||
|
||||
rec = bootvar_add_boot_rec(data, (size_t)len);
|
||||
if (!rec)
|
||||
return -EBOOT_VAR_ERR;
|
||||
|
||||
if (bootvar_push_to_boot_order(rec))
|
||||
return -EBOOT_VAR_ERR;
|
||||
|
||||
if (varname && size) {
|
||||
size_t len = strlen(rec->name);
|
||||
if (len < size) {
|
||||
snprintf(varname, len + 1, "%s", rec->name);
|
||||
} else {
|
||||
LOG_ERROR("%lu bytes is not enough. Need %lu.", size, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bootvar_init(void)
|
||||
{
|
||||
char *test_mode_env = getenv(CBM_BOOTVAR_TEST_MODE_VAR);
|
||||
if (test_mode_env && !strncmp(test_mode_env, "yes", 4)) {
|
||||
LOG_INFO("EFI variables support is disabled: " CBM_BOOTVAR_TEST_MODE_VAR " is set");
|
||||
test_mode = 1;
|
||||
}
|
||||
if (test_mode)
|
||||
return 0;
|
||||
if (efi_variables_supported() < 0)
|
||||
return -EBOOT_VAR_NOSUP;
|
||||
if (bootvar_read_boot_recs() < 0)
|
||||
return -EBOOT_VAR_ERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bootvar_destroy(void)
|
||||
{
|
||||
if (test_mode)
|
||||
return;
|
||||
bootvar_free_boot_recs();
|
||||
}
|
||||
|
||||
/* vim: set nosi noai cin ts=8 sw=8 et tw=80: */
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of clr-boot-manager.
|
||||
*
|
||||
* Copyright © 2017 Intel Corporation
|
||||
*
|
||||
* clr-boot-manager is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define EBOOT_VAR_ERR 1 /* general error */
|
||||
#define EBOOT_VAR_NOSUP 127 /* EFI vars not supported */
|
||||
|
||||
int bootvar_init(void);
|
||||
void bootvar_destroy(void);
|
||||
int bootvar_create(const char *, const char *, char *, size_t);
|
||||
|
||||
/* vim: set nosi noai cin ts=8 sw=8 et tw=80: */
|
||||
+3
-3
@@ -59,9 +59,9 @@ char *get_parent_disk(char *path);
|
||||
char *get_legacy_boot_device(char *path);
|
||||
|
||||
/**
|
||||
* Determine if the files match in content by comparing
|
||||
* their checksums
|
||||
*/
|
||||
* Determine if the files match in content by comparing
|
||||
* their checksums
|
||||
*/
|
||||
bool cbm_files_match(const char *p1, const char *p2);
|
||||
|
||||
/**
|
||||
|
||||
@@ -134,6 +134,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
s = core_suite();
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
|
||||
@@ -430,6 +430,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
cbm_blkid_set_vtable(&BlkidTestOps);
|
||||
cbm_system_set_vtable(&SystemTestOps);
|
||||
|
||||
|
||||
@@ -110,6 +110,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
s = core_suite();
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
|
||||
@@ -261,6 +261,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
cbm_blkid_set_vtable(&blkid_ops);
|
||||
cbm_system_set_vtable(&SystemTestOps);
|
||||
|
||||
|
||||
@@ -294,6 +294,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
cbm_blkid_set_vtable(&blkid_ops);
|
||||
cbm_system_set_vtable(&SystemTestOps);
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
s = core_suite();
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
|
||||
@@ -241,6 +241,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
s = core_suite();
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
|
||||
@@ -441,6 +441,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
s = core_suite();
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
|
||||
@@ -453,6 +453,9 @@ int main(void)
|
||||
setenv("CBM_DEBUG", "1", 1);
|
||||
cbm_log_init(stderr);
|
||||
|
||||
/* Turn off the EFI variable manipulation. */
|
||||
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
|
||||
|
||||
cbm_blkid_set_vtable(&BlkidTestOps);
|
||||
cbm_system_set_vtable(&SystemTestOps);
|
||||
|
||||
|
||||
+38
-6
@@ -14,6 +14,7 @@
|
||||
#include <assert.h>
|
||||
#include <check.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -59,15 +60,20 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Systemd support
|
||||
* Systemd support, including shim-systemd two-stage
|
||||
*/
|
||||
#if defined(HAVE_SYSTEMD_BOOT)
|
||||
#if defined(HAVE_SHIM_SYSTEMD_BOOT)
|
||||
#define ESP_BOOT_DIR BOOT_FULL "/" KERNEL_NAMESPACE
|
||||
#define ESP_BOOT_STUB ESP_BOOT_DIR "/bootloader" EFI_STUB_SUFFIX_L
|
||||
#define SHIM_BOOT_COPY_DIR PLAYGROUND_ROOT "/usr/lib/shim"
|
||||
#else
|
||||
#define ESP_BOOT_DIR EFI_START "/systemd"
|
||||
#define ESP_BOOT_STUB ESP_BOOT_DIR "/systemd-boot" EFI_STUB_SUFFIX_L
|
||||
#endif /* HAVE_SHIM_SYSTEMD_BOOT */
|
||||
|
||||
#define BOOT_COPY_TARGET PLAYGROUND_ROOT "/usr/lib/systemd/boot/efi/systemd-boot" EFI_STUB_SUFFIX_L
|
||||
#define BOOT_COPY_DIR PLAYGROUND_ROOT "/usr/lib/systemd/boot/efi"
|
||||
|
||||
/**
|
||||
* gummiboot support
|
||||
*/
|
||||
@@ -126,17 +132,21 @@ static void push_syslinux(void)
|
||||
|
||||
void confirm_bootloader(void)
|
||||
{
|
||||
#if !defined(HAVE_SHIM_SYSTEMD_BOOT)
|
||||
fail_if(!noisy_file_exists(EFI_STUB_MAIN), "Main EFI stub missing");
|
||||
#endif
|
||||
fail_if(!noisy_file_exists(ESP_BOOT_DIR), "ESP target directory missing");
|
||||
fail_if(!noisy_file_exists(ESP_BOOT_STUB), "ESP target stub missing");
|
||||
}
|
||||
|
||||
bool confirm_bootloader_match(void)
|
||||
{
|
||||
#if !defined(HAVE_SHIM_SYSTEMD_BOOT)
|
||||
if (!cbm_files_match(BOOT_COPY_TARGET, EFI_STUB_MAIN)) {
|
||||
fprintf(stderr, "EFI_STUB_MAIN doesn't match the source\n");
|
||||
return false;
|
||||
}
|
||||
#endif /* !HAVE_SHIM_SYSTEMD_BOOT */
|
||||
if (!cbm_files_match(BOOT_COPY_TARGET, ESP_BOOT_STUB)) {
|
||||
fprintf(stderr, "ESP_BOOT_STUB(vendor) doesn't match the source\n");
|
||||
return false;
|
||||
@@ -322,6 +332,24 @@ bool push_bootloader_update(int revision)
|
||||
fprintf(stderr, "Failed to update bootloader: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#if defined(HAVE_SHIM_SYSTEMD_BOOT)
|
||||
{
|
||||
int i;
|
||||
char path[PATH_MAX];
|
||||
char *files[3] = { "fb", "mm", "shim" };
|
||||
if (!nc_file_exists(SHIM_BOOT_COPY_DIR) && !nc_mkdir_p(SHIM_BOOT_COPY_DIR, 0755))
|
||||
return false;
|
||||
for (i = 0; i < 3; i++) {
|
||||
snprintf(path,
|
||||
PATH_MAX,
|
||||
"%s/%s" EFI_STUB_SUFFIX_L,
|
||||
SHIM_BOOT_COPY_DIR,
|
||||
files[i]);
|
||||
if (!file_set_text(path, text))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SHIM_SYSTEMD_BOOT */
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -449,14 +477,18 @@ int kernel_installed_files_count(BootManager *manager, PlaygroundKernel *kernel)
|
||||
autofree(char) *kernel_blob_legacy = NULL;
|
||||
autofree(char) *initrd_file = NULL;
|
||||
autofree(char) *initrd_file_legacy = NULL;
|
||||
/* where the kernel files are expected to be found on the ESP */
|
||||
char *esp_path = manager->bootloader->get_kernel_destination
|
||||
? manager->bootloader->get_kernel_destination(manager)
|
||||
: "efi/" KERNEL_NAMESPACE;
|
||||
const char *vendor = NULL;
|
||||
int file_count = 0;
|
||||
|
||||
vendor = boot_manager_get_vendor_prefix(manager);
|
||||
|
||||
kernel_blob = string_printf("%s/efi/%s/kernel-%s.%s.%s-%d",
|
||||
kernel_blob = string_printf("%s/%s/kernel-%s.%s.%s-%d",
|
||||
BOOT_FULL,
|
||||
KERNEL_NAMESPACE,
|
||||
esp_path,
|
||||
KERNEL_NAMESPACE,
|
||||
kernel->ktype,
|
||||
kernel->version,
|
||||
@@ -470,9 +502,9 @@ int kernel_installed_files_count(BootManager *manager, PlaygroundKernel *kernel)
|
||||
kernel->version,
|
||||
kernel->release);
|
||||
|
||||
initrd_file = string_printf("%s/efi/%s/initrd-%s.%s.%s-%d",
|
||||
initrd_file = string_printf("%s/%s/initrd-%s.%s.%s-%d",
|
||||
BOOT_FULL,
|
||||
KERNEL_NAMESPACE,
|
||||
esp_path,
|
||||
KERNEL_NAMESPACE,
|
||||
kernel->ktype,
|
||||
kernel->version,
|
||||
|
||||
Reference in New Issue
Block a user