File 0001-blscfg-read-fragments-in-order.patch of Package grub2

From 3f30cc565773e11d8eb0f4e68743b13527f33478 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 14 Apr 2025 08:52:26 +0800
Subject: [PATCH] blscfg: read fragments in order

---
 grub-core/commands/blscfg.c | 164 ++++++++++++++++++++++--------------
 1 file changed, 103 insertions(+), 61 deletions(-)

diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 343c7ae989..10996722cf 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -55,6 +55,15 @@ struct keyval
 
 static struct bls_entry *entries = NULL;
 
+struct bls_fragment
+{
+  struct bls_fragment *next;
+  struct bls_fragment *prev;
+  char *filename;
+};
+typedef struct bls_fragment *bls_fragment_t;
+static bls_fragment_t fragments;
+
 #define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
 
 /* BLS appears to make paths relative to the filesystem that snippets are
@@ -466,69 +475,41 @@ struct read_entry_info {
   grub_file_t file;
 };
 
-static int read_entry (
-    const char *filename,
-    const struct grub_dirhook_info *dirhook_info UNUSED,
-    void *data)
+static int
+read_entry (const char *filename)
 {
   grub_size_t m = 0, n, clip = 0;
   int rc = 0;
   char *p = NULL;
   grub_file_t f = NULL;
   struct bls_entry *entry;
-  struct read_entry_info *info = (struct read_entry_info *)data;
-
-  grub_dprintf ("blscfg", "filename: \"%s\"\n", filename);
+  char *slash;
 
-  n = grub_strlen (filename);
+  grub_dprintf ("blscfg", "read_entry: \"%s\"\n", filename);
 
-  if (info->file)
-    {
-      f = info->file;
-    }
-  else
-    {
-      if (filename[0] == '.')
-	return 0;
+  f = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG);
 
-      if (n <= 5)
-	return 0;
-
-      if (grub_strcmp (filename + n - 5, ".conf") != 0)
-	return 0;
-
-      p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
-
-      f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
-      if (!f)
-	goto finish;
-    }
+  if (!f)
+    goto finish;
 
   entry = grub_zalloc (sizeof (*entry));
   if (!entry)
     goto finish;
 
-  if (info->file)
-    {
-      char *slash;
+  /* Strip .conf */
+  n = grub_strlen (filename);
 
-      if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0)
-	clip = 5;
+  if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0)
+    clip = 5;
 
-      slash = grub_strrchr (filename, '/');
-      if (!slash)
-	slash = grub_strrchr (filename, '\\');
+  slash = grub_strrchr (filename, '/');
+  if (!slash)
+    slash = grub_strrchr (filename, '\\');
 
-      while (*slash == '/' || *slash == '\\')
-	slash++;
+  while (*slash == '/' || *slash == '\\')
+    slash++;
 
-      m = slash ? slash - filename : 0;
-    }
-  else
-    {
-      m = 0;
-      clip = 5;
-    }
+  m = slash ? slash - filename : 0;
   n -= m;
 
   entry->filename = grub_strndup(filename + m, n - clip);
@@ -573,10 +554,7 @@ static int read_entry (
       if (rc < 0)
 	break;
     }
-  
-    if (info->devid)
-      entry->devid = grub_strdup(info->devid);
-
+    entry->devid = grub_file_get_device_name (filename);
     if (!rc)
       bls_add_entry(entry);
 
@@ -590,6 +568,73 @@ finish:
   return 0;
 }
 
+static int
+collect_fragments (
+    const char *filename,
+    const struct grub_dirhook_info *dirhook_info UNUSED,
+    void *data)
+{
+  grub_size_t n;
+  char *p = NULL;
+  struct read_entry_info *info = (struct read_entry_info *)data;
+  bls_fragment_t fragment, f, last;
+
+  if (filename[0] == '.')
+    return 0;
+
+  n = grub_strlen (filename);
+  if (n <= 5)
+    return 0;
+
+  if (grub_strcmp (filename + n - 5, ".conf") != 0)
+    return 0;
+
+  p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
+
+  fragment = grub_zalloc (sizeof (*fragment));
+  fragment->filename = grub_strdup (p);
+
+  if (!fragments)
+    {
+      fragments = fragment;
+      return 0;
+    }
+
+  FOR_LIST_ELEMENTS (f, fragments)
+    {
+      int rc;
+      rc = grub_strcmp(fragment->filename, f->filename);
+      if (!rc)
+	{
+	  grub_free (fragment);
+	  return 0;
+	}
+      if (rc < 0)
+	{
+	  fragment->next = f;
+	  if (f->prev)
+	    f->prev->next = fragment;
+	  fragment->prev = f->prev;
+	  f->prev = fragment;
+	  if (f == fragments)
+	    {
+	      fragments = fragment;
+	      fragment->prev = NULL;
+	    }
+	  return 0;
+	}
+      last = f;
+    }
+
+  if (last)
+    {
+      last->next = fragment;
+      fragment->prev = last;
+    }
+
+  return 0;
+}
+
 static grub_envblk_t saved_env = NULL;
 
 static int UNUSED
@@ -1007,6 +1052,7 @@ static int find_entry (struct find_entry_info *info)
   const char *blsdir = info->dirname;
   int fallback = 0;
   int r = 0;
+  bls_fragment_t fragment;
 
   if (!blsdir) {
     blsdir = grub_env_get ("blsdir");
@@ -1024,8 +1070,14 @@ static int find_entry (struct find_entry_info *info)
   read_entry_info.devid = info->devid;
 
 read_fallback:
-  r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry,
+  r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, collect_fragments,
 			 &read_entry_info);
+  FOR_LIST_ELEMENTS (fragment, fragments)
+    {
+      grub_dprintf ("blscfg", "read_entry: %s\n", fragment->filename);
+      read_entry (fragment->filename);
+    }
+
   if (r != 0) {
       grub_dprintf ("blscfg", "read_entry returned error\n");
       grub_err_t e;
@@ -1060,21 +1112,11 @@ bls_load_entries (const char *path)
       .fs = NULL,
       .dirname = NULL,
   };
-  struct read_entry_info rei = {
-      .devid = NULL,
-      .dirname = NULL,
-  };
 
   if (path) {
     len = grub_strlen (path);
     if (grub_strcmp (path + len - 5, ".conf") == 0) {
-      rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG);
-      if (!rei.file)
-	return grub_errno;
-      /*
-       * read_entry() closes the file
-       */
-      return read_entry(path, NULL, &rei);
+      return read_entry (path);
     } else if (path[0] == '(') {
       devid = path + 1;
 
-- 
2.49.0

openSUSE Build Service is sponsored by