8631a2
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
8631a2
From: Javier Martinez Canillas <javierm@redhat.com>
8631a2
Date: Fri, 11 May 2018 23:47:31 +0200
8631a2
Subject: [PATCH] Simplify BLS entry key val pairs lookup
8631a2
8631a2
The <key,value> pairs found in the BLS are being sorted but this isn't
8631a2
really needed and it makes the implementation complex and error prone.
8631a2
8631a2
For example, the current implementation has the following issues:
8631a2
8631a2
1) Fields not present in the grub2 menu entry
8631a2
8631a2
  linux /linuz
8631a2
  initrd /foo
8631a2
  initrd /bar
8631a2
8631a2
  load_video
8631a2
  set gfx_payload=keep
8631a2
  insmod gzio
8631a2
  linux /boot/linuz
8631a2
  initrd /boot/bar
8631a2
8631a2
2) Fields present but in the wrong order
8631a2
8631a2
  title Fedora (4.16.6-300.fc28.x86_64-tuned) 28 (Twenty Eight)
8631a2
  version 4.16.6-300.fc28.x86_64
8631a2
  linux /vmlinuz-4.16.6-300.fc28.x86_64
8631a2
  initrd /foo.img
8631a2
  initrd /bar.img
8631a2
  options $kernelopts
8631a2
  id fedora-20180430150025-4.16.6-300.fc28.x86_64
8631a2
8631a2
  load_video
8631a2
  set gfx_payload=keep
8631a2
  insmod gzio
8631a2
  linux /boot/vmlinuz-4.16.6-300.fc28.x86_64 $kernelopts
8631a2
  initrd /boot/bar.img /boot/foo.img
8631a2
8631a2
It's important to preserve the order in which fields have been defined
8631a2
in the BLS fragment since for some of the fields the order has meaning.
8631a2
For example, initramfs images have to be passed to the kernel in order
8631a2
that were defined in the BLS fragment.
8631a2
8631a2
This patch simplifies the <key,value> pairs storage and lookup. Rather
8631a2
than sorting and attempt to later figure out what's the expected order,
8631a2
just store it in the same order as they were defined in the BLS config
8631a2
file and return in that same order to callers when these look them up.
8631a2
8631a2
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
8631a2
---
8631a2
 grub-core/commands/blscfg.c | 88 ++++++++++-----------------------------------
8631a2
 1 file changed, 18 insertions(+), 70 deletions(-)
8631a2
8631a2
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
f6e916
index c52d2b2e0..fb08d8e4c 100644
8631a2
--- a/grub-core/commands/blscfg.c
8631a2
+++ b/grub-core/commands/blscfg.c
8631a2
@@ -169,84 +169,35 @@ static void bls_free_entry(struct bls_entry *entry)
8631a2
   grub_free (entry);
8631a2
 }
8631a2
 
8631a2
-static int keyval_cmp (const void *p0, const void *p1,
8631a2
-		       void *state UNUSED)
8631a2
-{
8631a2
-  const struct keyval *kv0 = *(struct keyval * const *)p0;
8631a2
-  const struct keyval *kv1 = *(struct keyval * const *)p1;
8631a2
-  int rc;
8631a2
-
8631a2
-  rc = grub_strcmp(kv0->key, kv1->key);
8631a2
-
8631a2
-  return rc;
8631a2
-}
8631a2
-
8631a2
 /* Find they value of the key named by keyname.  If there are allowed to be
8631a2
  * more than one, pass a pointer to an int set to -1 the first time, and pass
8631a2
  * the same pointer through each time after, and it'll return them in sorted
8631a2
- * order. */
8631a2
+ * order as defined in the BLS fragment file */
8631a2
 static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last)
8631a2
 {
8631a2
-  char *foo = (char *)"";
8631a2
-  struct keyval *kv = NULL, **kvp, key = {keyname, foo}, *keyp = &ke;;
8631a2
+  int idx, start = 0;
8631a2
+  struct keyval *kv = NULL;
8631a2
 
8631a2
-  /* if we've already found an entry that matches, just iterate */
8631a2
-  if (last && *last >= 0)
8631a2
-    {
8631a2
-      int next = ++last[0];
8631a2
+  if (last)
8631a2
+    start = *last + 1;
8631a2
 
8631a2
-      if (next == entry->nkeyvals)
8631a2
-	{
8631a2
-done:
8631a2
-	  *last = -1;
8631a2
-	  return NULL;
8631a2
-	}
8631a2
+  for (idx = start; idx < entry->nkeyvals; idx++) {
8631a2
+    kv = entry->keyvals[idx];
8631a2
 
8631a2
-      kv = entry->keyvals[next];
8631a2
-      if (grub_strcmp (keyname, kv->key))
8631a2
-	goto done;
8631a2
+    if (!grub_strcmp (keyname, kv->key))
8631a2
+      break;
8631a2
+  }
8631a2
 
8631a2
-      return kv->val;
8631a2
-    }
8631a2
+  if (idx == entry->nkeyvals) {
8631a2
+    if (last)
8631a2
+      *last = -1;
8631a2
+    return NULL;
8631a2
+  }
8631a2
 
8631a2
-  kvp = grub_bsearch(&keyp, &entry->keyvals[0], entry->nkeyvals,
8631a2
-		    sizeof (struct keyval *), keyval_cmp, NULL);
8631a2
-  if (kvp)
8631a2
-    kv = *kvp;
8631a2
+  if (last)
8631a2
+    *last = idx;
8631a2
 
8631a2
-  if (kv)
8631a2
-    {
8631a2
-      /* if we've got uninitialized but present state, track back until we find
8631a2
-       * the first match */
8631a2
-      if (last)
8631a2
-	{
8631a2
-	  grub_dprintf("blscfg", "%s trying to find another entry because last was set\n", __func__);
8631a2
-	  /* figure out the position of this entry in the array */
8631a2
-	  int idx;
8631a2
-	  for (idx = 0 ; idx < entry->nkeyvals; idx++)
8631a2
-	    if (entry->keyvals[idx] == kv)
8631a2
-	      break;
8631a2
-	  *last = idx;
8631a2
-
8631a2
-	  while (idx > 0)
8631a2
-	    {
8631a2
-	      struct keyval *kvtmp = entry->keyvals[idx-1];
8631a2
-	      if (idx == 0 || grub_strcmp (keyname, kvtmp->key))
8631a2
-		{
8631a2
-		  /* if we're at the start, or if the previous entry doesn't
8631a2
-		   * match, then we're done */
8631a2
-		  *last = idx;
8631a2
-		  break;
8631a2
-		}
8631a2
-	      else
8631a2
-		/* but if it does match, keep going backwards */
8631a2
-		idx--;
8631a2
-	    }
8631a2
-	}
8631a2
-
8631a2
-      return kv->val;
8631a2
-    }
8631a2
-  return NULL;
8631a2
+  return kv->val;
8631a2
 }
8631a2
 
8631a2
 #define goto_return(x) ({ ret = (x); goto finish; })
8631a2
@@ -503,9 +454,6 @@ static int read_entry (
8631a2
 	break;
8631a2
     }
8631a2
 
8631a2
-  grub_qsort(&entry->keyvals[0], entry->nkeyvals, sizeof (struct keyval *),
8631a2
-	     keyval_cmp, NULL);
8631a2
-
8631a2
 finish:
8631a2
   grub_free (p);
8631a2