Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package grub2 for openSUSE:Factory checked in at 2025-04-29 16:39:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/grub2 (Old) and /work/SRC/openSUSE:Factory/.grub2.new.30101 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "grub2" Tue Apr 29 16:39:46 2025 rev:360 rq:1273319 version:2.12 Changes: -------- --- /work/SRC/openSUSE:Factory/grub2/grub2.changes 2025-04-24 17:25:14.580653304 +0200 +++ /work/SRC/openSUSE:Factory/.grub2.new.30101/grub2.changes 2025-04-29 16:39:54.332993295 +0200 @@ -1,0 +2,15 @@ +Fri Apr 25 17:44:31 UTC 2025 - Andreas Stieger <andreas.stie...@gmx.de> + +- grub2-common: use fuse3 + +------------------------------------------------------------------- +Wed Apr 23 09:50:10 UTC 2025 - Danilo Spinella <danilo.spine...@suse.com> + +- Add support for boot assessment, needed by health-checker + * grub2-bls-boot-counting.patch + * grub2-bls-boot-assessment.patch + * grub2-bls-boot-show-snapshot.patch + * grub2-blscfg-fix-hang.patch + * grub2-blscfg-set-efivars.patch + +------------------------------------------------------------------- New: ---- grub2-bls-boot-assessment.patch grub2-bls-boot-counting.patch grub2-bls-boot-show-snapshot.patch grub2-blscfg-fix-hang.patch grub2-blscfg-set-efivars.patch BETA DEBUG BEGIN: New: * grub2-bls-boot-counting.patch * grub2-bls-boot-assessment.patch * grub2-bls-boot-show-snapshot.patch New:- Add support for boot assessment, needed by health-checker * grub2-bls-boot-counting.patch * grub2-bls-boot-assessment.patch New: * grub2-bls-boot-assessment.patch * grub2-bls-boot-show-snapshot.patch * grub2-blscfg-fix-hang.patch New: * grub2-bls-boot-show-snapshot.patch * grub2-blscfg-fix-hang.patch * grub2-blscfg-set-efivars.patch New: * grub2-blscfg-fix-hang.patch * grub2-blscfg-set-efivars.patch BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ grub2.spec ++++++ --- /var/tmp/diff_new_pack.DG8Yzl/_old 2025-04-29 16:39:58.481167530 +0200 +++ /var/tmp/diff_new_pack.DG8Yzl/_new 2025-04-29 16:39:58.485167699 +0200 @@ -34,9 +34,9 @@ BuildRequires: fdupes BuildRequires: flex BuildRequires: freetype2-devel -BuildRequires: fuse-devel BuildRequires: gcc BuildRequires: glibc-devel +BuildRequires: pkgconfig(fuse3) %if 0%{?suse_version} >= 1140 BuildRequires: dejavu-fonts BuildRequires: gnu-unifont @@ -466,6 +466,11 @@ Patch293: grub2-string-initializer.patch Patch294: 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch Patch295: 0001-blscfg-read-fragments-in-order.patch +Patch296: grub2-bls-boot-counting.patch +Patch297: grub2-bls-boot-assessment.patch +Patch298: grub2-bls-boot-show-snapshot.patch +Patch299: grub2-blscfg-fix-hang.patch +Patch300: grub2-blscfg-set-efivars.patch %if 0%{?suse_version} < 1600 Requires: gettext-runtime @@ -853,7 +858,7 @@ PXE_MODULES="tftp http" CRYPTO_MODULES="luks luks2 gcry_rijndael gcry_sha1 gcry_sha256 gcry_sha512 crypttab" %ifarch %{efi} -CD_MODULES="${CD_MODULES} chain efifwsetup efinet read tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blscfg" +CD_MODULES="${CD_MODULES} chain efifwsetup efinet read tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blscfg blsbumpcounter" PXE_MODULES="${PXE_MODULES} efinet" %else CD_MODULES="${CD_MODULES} net ofnet" @@ -959,7 +964,7 @@ %{?sbat_generation:--sbat sbat.csv} \ -d grub-core \ all_video boot font gfxmenu gfxterm gzio halt jpeg minicmd normal part_gpt png reboot video \ - fat tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blscfg linux bli regexp loadenv test echo true sleep + fat tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blscfg blsbumpcounter linux bli regexp loadenv test echo true sleep %endif %ifarch x86_64 aarch64 ++++++ grub2-bls-boot-assessment.patch ++++++ Implement Automatic Boot Assessment for grub2-bls. https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT/ The entries are ordered first by the boot tries left, keeping the one without available tries (e.g. <entry>+0-3.conf) after the one without a boot counter or with a positive boot counter. After removing the boot counter from the release string, keep the ordering as it worked previously. Index: grub-2.12/grub-core/commands/blscfg.c =================================================================== --- grub-2.12.orig/grub-core/commands/blscfg.c +++ grub-2.12/grub-core/commands/blscfg.c @@ -323,9 +323,37 @@ finish: /* NULL string pointer returned if nothing found */ static void split_package_string (char *package_string, char **name, - char **version, char **release) + char **version, char **release, int *tries_left) { - char *package_version, *package_release; + char *package_version, *package_release, *tries_left_str, *tmp; + + *tries_left = -1; + /* Search for the start of the tries left, as per boot assessment */ + tries_left_str = grub_strrchr(package_string, '+'); + if (tries_left_str != NULL) + { + /* If there the number of tries available is after the number of tries left (e.g. +1-2) + stop the string at the '-' delimiter, so that strtol + does the parsing of the first part and skip the second */ + tmp = grub_strrchr(tries_left_str, '-'); + if (tmp != NULL) + { + *tmp = '\0'; + } + tmp = tries_left_str; + *tries_left = grub_strtol(++tmp, (const char **)&tmp, 10); + + /* Conversion failed */ + if (tmp == tries_left_str) + { + /* Reset the counter */ + *tries_left = -1; + } + else + { + *tries_left_str = '\0'; + } + } /* Release */ package_release = grub_strrchr (package_string, '-'); @@ -372,9 +401,23 @@ split_cmp(char *nvr0, char *nvr1, int ha int ret = 0; char *name0, *version0, *release0; char *name1, *version1, *release1; + int tries_left0; + int tries_left1; + + split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0, &tries_left0); + split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1, &tries_left1); - split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0); - split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1); + /* Check for systemd Automatic Boot Assessment + 0 has no tries left, while 1 doesn't have a boot count / still has tries left */ + if (tries_left0 == 0 && tries_left1 != 0) + { + return -1; + } + /* viceversa, b has no tries left */ + else if (tries_left0 != 0 && tries_left1 == 0) + { + return 1; + } if (has_name) { ++++++ grub2-bls-boot-counting.patch ++++++ Add a new bls_bumpcunter grub command that implement boot counting for bls entries. Boot counting, explained in systemd Automatic Boot Assessment, keep track of the avaiable tries for each entry and the number of attempted boot. The bls_bumpcunter command parse the entry id, check if there is a boot count enabled and update its value accordingly. Then, EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is used to rename the entry on the EFI partition. https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT/ Index: grub-2.12/include/grub/efi/filesystem.h =================================================================== --- /dev/null +++ grub-2.12/include/grub/efi/filesystem.h @@ -0,0 +1,155 @@ +/* + * GRUB -- GRand Unified Bootloader + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_EFI_TPM_HEADER +#define GRUB_EFI_TPM_HEADER 1 + +#include <grub/efi/api.h> +#include <grub/env.h> + +struct grub_efi_file_io_token { + grub_efi_event_t Event; + grub_efi_status_t Status; + grub_efi_uint64_t BufferSize; + void *Buffer; +}; + +typedef struct grub_efi_file_io_token grub_efi_file_io_token_t; + + +struct grub_efi_file_protocol +{ + grub_efi_uint64_t Revision; + + grub_efi_status_t + (__grub_efi_api *Open) (struct grub_efi_file_protocol *this, + struct grub_efi_file_protocol **new_handle, + grub_efi_char16_t *filename, + grub_efi_uint64_t open_mode, + grub_efi_uint64_t attributes); + + grub_efi_status_t + (__grub_efi_api *Close) (struct grub_efi_file_protocol *this); + + grub_efi_status_t + (__grub_efi_api *Delete) (struct grub_efi_file_protocol *this); + + grub_efi_status_t + (__grub_efi_api *Read) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t *buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *Write) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t *buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *GetPosition) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t *position); + + grub_efi_status_t + (__grub_efi_api *SetPosition) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t position); + + grub_efi_status_t + (__grub_efi_api *GetInfo) (struct grub_efi_file_protocol *this, + grub_guid_t *information_type, + grub_efi_uint64_t *buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *SetInfo) (struct grub_efi_file_protocol *this, + grub_guid_t *information_type, + grub_efi_uint64_t buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *Flush) (struct grub_efi_file_protocol *this); + + grub_efi_status_t + (__grub_efi_api *OpenEx) (struct grub_efi_file_protocol *this, + struct grub_efi_file_protocol **new_handle, + grub_efi_char16_t *filename, + grub_efi_uint64_t open_mode, + grub_efi_uint64_t attributes, + grub_efi_file_io_token_t *token); + + grub_efi_status_t + (__grub_efi_api *ReadEx) (struct grub_efi_file_protocol *this, + grub_efi_file_io_token_t *token); + + grub_efi_status_t + (__grub_efi_api *WriteEx) (struct grub_efi_file_protocol *this, + grub_efi_file_io_token_t *token); + + grub_efi_status_t + (__grub_efi_api *FlushEx) (struct grub_efi_file_protocol *this, + grub_efi_file_io_token_t *token); +}; + +typedef struct grub_efi_file_protocol grub_efi_file_protocol_t; + +/******************************************************* + Open Modes + ******************************************************/ +#define GRUB_EFI_FILE_MODE_READ 0x0000000000000001 +#define GRUB_EFI_FILE_MODE_WRITE 0x0000000000000002 +#define GRUB_EFI_FILE_MODE_CREATE 0x8000000000000000 + +/******************************************************* + File Attributes + ******************************************************/ +#define GRUB_EFI_FILE_READ_ONLY 0x0000000000000001 +#define GRUB_EFI_FILE_HIDDEN 0x0000000000000002 +#define GRUB_EFI_FILE_SYSTEM 0x0000000000000004 +#define GRUB_EFI_FILE_RESERVED 0x0000000000000008 +#define GRUB_EFI_FILE_DIRECTORY 0x0000000000000010 +#define GRUB_EFI_FILE_ARCHIVE 0x0000000000000020 +#define GRUB_EFI_FILE_VALID_ATTR 0x0000000000000037 + +struct grub_efi_file_info { + grub_efi_uint64_t Size; + grub_efi_uint64_t FileSize; + grub_efi_uint64_t PhysicalSize; + grub_efi_time_t CreateTime; + grub_efi_time_t LastAccessTime; + grub_efi_time_t ModificationTime; + grub_efi_uint64_t Attribute; + grub_efi_char16_t FileName[]; +}; + +typedef struct grub_efi_file_info grub_efi_file_info_t; + +#define GRUB_EFI_FILE_INFO_ID \ + {0x09576e92,0x6d3f,0x11d2, \ + {0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} \ + } + +struct grub_efi_simple_file_system_protocol +{ + grub_efi_uint64_t Revision; + + grub_efi_status_t + (__grub_efi_api *OpenVolume) (struct grub_efi_simple_file_system_protocol *this, + struct grub_efi_file_protocol **root); +}; + +typedef struct grub_efi_simple_file_system_protocol grub_efi_simple_file_system_protocol_t; + + +#endif Index: grub-2.12/grub-core/commands/blscfg.c =================================================================== --- grub-2.12.orig/grub-core/commands/blscfg.c +++ grub-2.12/grub-core/commands/blscfg.c @@ -791,6 +791,8 @@ static void create_entry (struct bls_ent int i, index; bool add_dt_prefix = false; + char *bumpcounter = NULL; + grub_dprintf("blscfg", "%s got here\n", __func__); clinux = bls_get_val (entry, "linux", NULL); if (!clinux) @@ -949,6 +951,19 @@ static void create_entry (struct bls_ent grub_free(prefix); } + /* "bls_bumpcounter " + id + "\n" */ + int bumpcounter_size = sizeof("bls_bumpcounter ") + grub_strlen(id) + 1; + bumpcounter = grub_malloc(bumpcounter_size); + if (!bumpcounter) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + char *tmp = bumpcounter; + tmp = grub_stpcpy(tmp, "bls_bumpcounter "); + tmp = grub_stpcpy(tmp, id); + tmp = grub_stpcpy(tmp, "\n"); + grub_dprintf ("blscfg2", "devicetree %s for id:\"%s\"\n", dt, id); const char *sdval = grub_env_get("save_default"); @@ -961,7 +976,7 @@ static void create_entry (struct bls_ent "insmod gzio\n" "linux %s%s%s%s\n" #endif - "%s%s", + "%s%s%s", savedefault ? "savedefault\n" : "", #ifdef GRUB_MACHINE_EMU separate_boot ? GRUB_BOOT_DEVICE : "", @@ -969,7 +984,8 @@ static void create_entry (struct bls_ent bootdev, #endif clinux, options ? " " : "", options ? options : "", - initrd ? initrd : "", dt ? dt : ""); + bumpcounter ? bumpcounter : "", initrd ? initrd : "", + dt ? dt : ""); grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, 0, &index, entry); grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id); @@ -987,6 +1003,7 @@ finish: grub_free (argv); grub_free (src); grub_free (bootdev); + grub_free (bumpcounter); } struct find_entry_info { Index: grub-2.12/grub-core/commands/blsbumpcounter.c =================================================================== --- /dev/null +++ grub-2.12/grub-core/commands/blsbumpcounter.c @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ + +/* blsbumpcounter.c - implementation of boot counting for the Automatic Boot Assessment */ + +/* + * GRUB -- GRand Unified Bootloader + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/extcmd.h> +#include <grub/dl.h> + +#include <stddef.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + + +static grub_err_t +grub_cmd_bumpcounters (grub_extcmd_context_t ctxt UNUSED, + int argc UNUSED, char **args UNUSED) +{ + /* placeholder, as blsbumpcounter only work on EFI platforms */ + return GRUB_ERR_NONE; +} + + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(blsbumpcounter) +{ + cmd = grub_register_extcmd ("bls_bumpcounter", + grub_cmd_bumpcounters, + 0, + NULL, + N_("Bump the boot entry counting (only works on EFI)."), + NULL); +} + +GRUB_MOD_FINI(blsbumpcounter) +{ + grub_unregister_extcmd (cmd); +} Index: grub-2.12/grub-core/Makefile.core.def =================================================================== --- grub-2.12.orig/grub-core/Makefile.core.def +++ grub-2.12/grub-core/Makefile.core.def @@ -858,6 +858,13 @@ module = { }; module = { + name = blsbumpcounter; + common = commands/blsbumpcounter.c; + efi = commands/efi/blsbumpcounter.c; +}; + + +module = { name = boot; common = commands/boot.c; i386_pc = lib/i386/pc/biosnum.c; Index: grub-2.12/grub-core/commands/efi/blsbumpcounter.c =================================================================== --- /dev/null +++ grub-2.12/grub-core/commands/efi/blsbumpcounter.c @@ -0,0 +1,252 @@ +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ + +/* bls.c - implementation of the boot loader spec */ + +/* + * GRUB -- GRand Unified Bootloader + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/extcmd.h> +#include <grub/fs.h> +#include <grub/env.h> +#include <grub/lib/envblk.h> +#include <grub/efi/api.h> +#include <grub/efi/efi.h> +#include <grub/efi/filesystem.h> + +#include <stddef.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_BLS_CONFIG_PATH "\\loader\\entries\\" + +#define GRUB_EFI_LOADER_GUID \ + { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } } + +static grub_guid_t grub_simple_file_system_guid = GRUB_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static grub_guid_t grub_efi_loader_guid = GRUB_EFI_LOADER_GUID; + +static grub_err_t +grub_cmd_bumpcounters (grub_extcmd_context_t ctxt UNUSED, + int argc UNUSED, char **args UNUSED) +{ + grub_efi_file_info_t *file_info = NULL; + grub_efi_file_protocol_t *handle = NULL; + grub_efi_file_protocol_t *root = NULL; + grub_efi_simple_file_system_protocol_t *volume = NULL; + char* id = NULL; + + grub_dprintf("bls_bumpcounter", "starting bumpcounter\n"); + /* There should be exactly two arguments, the entry that is getting booted and the disk where + it can be found */ + if (argc != 1) { + grub_dprintf("bls_bumpcounter", "one argument should be passed\n"); + return GRUB_ERR_BAD_ARGUMENT; + } + id = args[0]; + + /* Look for the start of the count + If no '+' symbol has been found, the boot counting isn't enabled for the selected entry */ + if (grub_strrchr(id, '+') == NULL) { + grub_dprintf("bls_bumpcounter", "boot counting is not in effect for id %s\n", id); + return GRUB_ERR_NONE; + } + + grub_efi_loaded_image_t *image = NULL; + grub_dprintf("bls_bumpcounter", "Using loaded EFI image device\n"); + image = grub_efi_get_loaded_image (grub_efi_image_handle); + + if (!image) { + grub_dprintf("bls_bumpcounter", "grub_efi_get_loaded_image failed\n"); + return 0; + } + + grub_efi_status_t err; + grub_efi_boot_services_t *bs; + bs = grub_efi_system_table->boot_services; + err = bs->handle_protocol (image->device_handle, + (void *) &grub_simple_file_system_guid, (void *) &volume); + if (err != GRUB_EFI_SUCCESS) { + grub_dprintf("bls_bumpcounter", "Cannot get handle to EFI_SIMPLE_FILE_SYSTEM_PROTOCOL: %lu\n", (unsigned long)err); + return GRUB_ERR_BAD_DEVICE; + } + volume->OpenVolume(volume, &root); + if (err != GRUB_EFI_SUCCESS) { + grub_dprintf("bls_bumpcounter", "Cannot open the volume: %lu\n", (unsigned long)err); + return GRUB_ERR_BAD_DEVICE; + } + + char *blsdir = (char *)grub_env_get ("blsdir"); + char *tmp = NULL; + if (blsdir) { + tmp = blsdir; + while (*tmp) { + if (*tmp == '/') { + /* Replace linux path delimiter (/) with EFI compatible (\) */ + *tmp = '\\'; + } + tmp++; + } + } else { + blsdir = (char *)GRUB_BLS_CONFIG_PATH; + } + + unsigned long int len = grub_strlen(blsdir) + grub_strlen(id) + sizeof(".conf") + 1; + grub_efi_char16_t* old_path = grub_malloc(len * sizeof(grub_efi_char16_t)); + if (!old_path) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + grub_efi_char16_t* tmp_path = old_path; + tmp = blsdir; + while (*tmp) { + *tmp_path++ = (grub_efi_char16_t)*tmp++; + } + tmp = id; + while (*tmp) { + *tmp_path++ = (grub_efi_char16_t)*tmp++; + } + static const char* ext = ".conf"; + tmp = (char *)ext; + while (*tmp) { + *tmp_path++ = (grub_efi_char16_t)*tmp++; + } + *tmp_path = (grub_efi_char16_t)'\0'; + + err = root->Open(root, &handle, old_path, GRUB_EFI_FILE_MODE_READ|GRUB_EFI_FILE_MODE_WRITE, 0); + grub_free(old_path); + if (err != GRUB_EFI_SUCCESS) { + grub_dprintf("bls_bumpcounter", "Cannot open the entry %s%s.conf : %lu\n", blsdir, id, (unsigned long)err); + goto finish; + } + + /* Just like get_file_info works in systemd:src/boot/efi/util.c, get the file_info */ + grub_efi_uint64_t size = offsetof(grub_efi_file_info_t, FileName) + 256U * sizeof(grub_efi_char16_t); + file_info = grub_malloc(size); + if (!file_info) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + grub_guid_t grub_efi_file_info_guid = GRUB_EFI_FILE_INFO_ID; + err = handle->GetInfo(handle, &grub_efi_file_info_guid, &size, file_info); + if (err == GRUB_EFI_BUFFER_TOO_SMALL) { + grub_free(file_info); + file_info = grub_malloc(size); + if (!file_info) { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + err = handle->GetInfo(handle, &grub_efi_file_info_guid, &size, file_info); + } + + if (err != GRUB_EFI_SUCCESS) { + grub_dprintf("bls_bumpcounter", "Cannot get the file_info of the entry: %lu\n", (unsigned long)err); + goto finish; + } + + /* Calculate the new filename with the bumped counter + Look for the start of the count */ + tmp = grub_strrchr(id, '+'); + *tmp = '\0'; + int tries = -1; + int tries_left = grub_strtol(++tmp, (const char**) &tmp, 10); + /* The parsing succeeded */ + if (tmp != NULL) { + if (tries_left > 0) { + tries_left--; + } + if (*tmp == '-') { + tmp++; + tries = grub_strtol(tmp, (const char**) &tmp, 10); + if (tmp != NULL) { + tries++; + } else { + tries = -1; + } + } + } else { + goto finish; + } + + char *new_path; + if (tries == -1) { + /* This is the first try, rename accordingly */ + new_path = grub_xasprintf ("%s+%d-1.conf", id, tries_left); + } else { + new_path = grub_xasprintf ("%s+%d-%d.conf", id, tries_left, tries); + } + grub_dprintf("bls_bumpcounter", "renaming entry to %s\n", new_path); + + /* Copy the new filename into the file_info struct */ + char* src = new_path; + grub_efi_char16_t *dst = file_info->FileName; + while (*src) { + *dst++ = (grub_efi_char16_t) *src++; + } + *dst = (grub_efi_char16_t) '\0'; + + handle->SetInfo(handle, &grub_efi_file_info_guid, size, file_info); + + if (err != GRUB_EFI_SUCCESS) { + grub_dprintf("bls_bumpcounter", "Cannot rename file: %lu\n", (unsigned long)err); + goto finish; + } + + handle->Flush(handle); + grub_dprintf("bls_bumpcounter", "entry renamed\n"); + handle->Close(handle); + + char* loader_boot_count_path = grub_xasprintf("%s%s", blsdir, new_path); + grub_free(new_path); + grub_efi_set_variable_to_string("LoaderBootCountPath", &grub_efi_loader_guid, loader_boot_count_path, + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | + GRUB_EFI_VARIABLE_RUNTIME_ACCESS); + grub_free(loader_boot_count_path); + + if (err != GRUB_EFI_SUCCESS) { + goto finish; + } + + grub_free(file_info); + + return GRUB_ERR_NONE; + +finish: + grub_free(file_info); + + return GRUB_ERR_BAD_DEVICE; +} + + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(blsbumpcounter) +{ + grub_dprintf("bls_bumpcounter", "%s got here\n", __func__); + cmd = grub_register_extcmd ("bls_bumpcounter", + grub_cmd_bumpcounters, + 0, + NULL, + N_("Bump the boot entry counting."), + NULL); +} + +GRUB_MOD_FINI(blsbumpcounter) +{ + grub_unregister_extcmd (cmd); +} ++++++ grub2-bls-boot-show-snapshot.patch ++++++ Index: grub-2.12/grub-core/commands/blscfg.c =================================================================== --- grub-2.12.orig/grub-core/commands/blscfg.c +++ grub-2.12/grub-core/commands/blscfg.c @@ -810,6 +810,7 @@ static void create_entry (struct bls_ent const char **argv = NULL; char *title = NULL; + char *version = NULL; char *clinux = NULL; char *options = NULL; char **initrds = NULL; @@ -853,7 +854,9 @@ static void create_entry (struct bls_ent if (dotconf) dotconf[0] = '\0'; - title = bls_get_val (entry, "title", NULL); + title = grub_strdup(bls_get_val (entry, "title", NULL)); + version = bls_get_val (entry, "version", NULL); + title = version ? grub_xasprintf("%s (%s)", title, version) : title; options = expand_val (bls_get_val (entry, "options", NULL)); if (!options) @@ -1040,6 +1043,7 @@ finish: grub_free (devicetree); grub_free (initrds); grub_free (options); + grub_free (title); grub_free (classes); grub_free (args); grub_free (argv); ++++++ grub2-blscfg-fix-hang.patch ++++++ Grub2 was hanging due to a infinite loop on incorrect entries. Entries that contained the string ".conf" but did not end with it were causing the loop to never exit. Move dotconf pointer up if it doesn't trigger the loop exit condition so that grub_strstr can return a NULL pointer at some point. Index: grub-2.12/grub-core/commands/blscfg.c =================================================================== --- grub-2.12.orig/grub-core/commands/blscfg.c +++ grub-2.12/grub-core/commands/blscfg.c @@ -850,7 +850,7 @@ static void create_entry (struct bls_ent do { dotconf = grub_strstr(dotconf, ".conf"); - } while (dotconf != NULL && dotconf[5] != '\0'); + } while (dotconf != NULL && dotconf[5] != '\0' && *(++dotconf)); if (dotconf) dotconf[0] = '\0'; ++++++ grub2-blscfg-set-efivars.patch ++++++ Set the EFI variables LoaderEntries and LoaderEntrySelected to follow systemd-boot implementation and make bootctl work. Index: grub-2.12/grub-core/commands/blscfg.c =================================================================== --- grub-2.12.orig/grub-core/commands/blscfg.c +++ grub-2.12/grub-core/commands/blscfg.c @@ -47,6 +47,14 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BOOT_DEVICE "($root)" #endif +#ifdef GRUB_MACHINE_EFI +#include <grub/efi/efi.h> +#define GRUB_EFI_LOADER_GUID \ + { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } } + +static grub_guid_t grub_efi_loader_guid = GRUB_EFI_LOADER_GUID; +#endif + struct keyval { const char *key; @@ -1223,6 +1231,12 @@ bls_create_entries (bool show_default, b const char *def_entry = NULL; struct bls_entry *entry = NULL; int idx = 0; +#ifdef GRUB_MACHINE_EFI + int size = 0; + grub_efi_char16_t *efi_entries = NULL; + grub_efi_char16_t *p = NULL; + char* tmp = NULL; +#endif def_entry = grub_env_get("default"); @@ -1238,10 +1252,38 @@ bls_create_entries (bool show_default, b (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) { create_entry(entry); entry->visible = 1; +#ifdef GRUB_MACHINE_EFI + size += grub_strlen(entry->filename) + 1; +#endif } idx++; } +#ifdef GRUB_MACHINE_EFI + efi_entries = grub_malloc(size * sizeof(grub_efi_char16_t)); + if (efi_entries == NULL) { + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't find space for LoaderEntries efi variable"); + } + p = efi_entries; + FOR_BLS_ENTRIES(entry) { + if (entry->visible) { + tmp = entry->filename; + while (*tmp) { + *p++ = (grub_efi_char16_t) *tmp++; + } + *p++ = (grub_efi_char16_t) '\0'; + } + } + if (efi_entries + size + 1 == p) { + return grub_error(GRUB_ERR_BAD_NUMBER, "efi entries value is not correct"); + } + grub_efi_set_variable_with_attributes("LoaderEntries", &grub_efi_loader_guid, + efi_entries, size * sizeof(grub_efi_char16_t), + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | + GRUB_EFI_VARIABLE_RUNTIME_ACCESS); +#endif + return GRUB_ERR_NONE; } Index: grub-2.12/grub-core/commands/efi/blsbumpcounter.c =================================================================== --- grub-2.12.orig/grub-core/commands/efi/blsbumpcounter.c +++ grub-2.12/grub-core/commands/efi/blsbumpcounter.c @@ -60,8 +60,14 @@ grub_cmd_bumpcounters (grub_extcmd_conte /* Look for the start of the count If no '+' symbol has been found, the boot counting isn't enabled for the selected entry */ + char* new_path = grub_xasprintf ("%s.conf", id); + grub_efi_set_variable_to_string("LoaderEntrySelected", &grub_efi_loader_guid, new_path, + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | + GRUB_EFI_VARIABLE_RUNTIME_ACCESS); + grub_free(new_path); if (grub_strrchr(id, '+') == NULL) { grub_dprintf("bls_bumpcounter", "boot counting is not in effect for id %s\n", id); + return GRUB_ERR_NONE; } @@ -183,7 +189,6 @@ grub_cmd_bumpcounters (grub_extcmd_conte goto finish; } - char *new_path; if (tries == -1) { /* This is the first try, rename accordingly */ new_path = grub_xasprintf ("%s+%d-1.conf", id, tries_left);