diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..20be72c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/8.40-1.tar.gz
diff --git a/.grubby.metadata b/.grubby.metadata
new file mode 100644
index 0000000..6085fc6
--- /dev/null
+++ b/.grubby.metadata
@@ -0,0 +1 @@
+97ae8d113b74538c05f05083dcff4f44012fd0cd SOURCES/8.40-1.tar.gz
diff --git a/SOURCES/0001-Set-envFile-from-env-when-bootloader-is-not-specifie.patch b/SOURCES/0001-Set-envFile-from-env-when-bootloader-is-not-specifie.patch
new file mode 100644
index 0000000..6873af8
--- /dev/null
+++ b/SOURCES/0001-Set-envFile-from-env-when-bootloader-is-not-specifie.patch
@@ -0,0 +1,30 @@
+From b5c0a31ae38c2c42f0dea8c2d7282694f020e976 Mon Sep 17 00:00:00 2001
+From: "Brian C. Lane" <bcl@redhat.com>
+Date: Mon, 13 Apr 2015 13:57:33 -0700
+Subject: [PATCH 01/55] Set envFile from --env when bootloader is not specified
+
+---
+ grubby.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index d4ebb86168d..53fe9250e27 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -4423,9 +4423,11 @@ int main(int argc, const char ** argv) {
+     }
+ 
+     if (!cfi) {
+-        if (grub2FindConfig(&grub2ConfigType))
++        if (grub2FindConfig(&grub2ConfigType)) {
+ 	    cfi = &grub2ConfigType;
+-	else
++	    if (envPath)
++		cfi->envFile = envPath;
++        } else
+       #ifdef __ia64__
+ 	    cfi = &eliloConfigType;
+       #elif __powerpc__
+-- 
+2.17.1
+
diff --git a/SOURCES/0002-add-README-with-description-of-the-test-suite.patch b/SOURCES/0002-add-README-with-description-of-the-test-suite.patch
new file mode 100644
index 0000000..9006808
--- /dev/null
+++ b/SOURCES/0002-add-README-with-description-of-the-test-suite.patch
@@ -0,0 +1,91 @@
+From 9c9587feca7413b34498064db19d796e1c402b51 Mon Sep 17 00:00:00 2001
+From: Alexander Todorov <atodorov@redhat.com>
+Date: Thu, 11 Jun 2015 08:45:37 -0400
+Subject: [PATCH 02/55] add README with description of the test suite
+
+---
+ README.rst | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 72 insertions(+)
+ create mode 100644 README.rst
+
+diff --git a/README.rst b/README.rst
+new file mode 100644
+index 00000000000..a5743ff2f96
+--- /dev/null
++++ b/README.rst
+@@ -0,0 +1,72 @@
++grubby is a command line tool for updating and displaying information about
++the configuration files for the grub, lilo, elilo (ia64), yaboot (powerpc)
++and zipl (s390) boot loaders. It is primarily designed to be used from scripts
++which install new kernels and need to find information about the current boot
++environment.
++
++
++Testing grubby
++==============
++
++To execute the integrated test suite from inside the source directory run the
++command::
++
++    make test
++
++
++Test Suite Architecture
++------------------------
++
++grubby's test suite is written in Bash. The file `test.sh` contains several
++helper functions and a list of different test scenarios which are exercised
++upon execution. Important functions are:
++
++- oneTest() - test if the configuration generated by the supplied grubby
++  parameters matches a well known configuration file;
++
++- oneDisplayTest() - test grubby features that display some information,
++  checking grubby's output against well known values;
++
++- commandTest() - test if the output of some commands matches the provided
++  text. This function is only used for grub2 testing in a few places.
++
++
++Note: the test suite creates aliases for oneTest() and oneDisplayTest(), which
++are prefixed with the corresponding boot loader name. For example:
++grubTest(). eliloTest(), etc.
++
++The invocation syntax is::
++
++    testFunction config_file results_file --grubby --options
++
++For example the line::
++
++    grubTest grub.1 updargs/g1.1 --update-kernel=DEFAULT --args="root=/dev/hda1"
++    
++means execute the command::
++
++    ./grubby --grub --config-file tests/grub.1 --update-kernel=DEFAULT \
++    --args="root=/dev/hda1"
++
++and compare the resulting configuration with the file
++`tests/results/updargs/g1.1`.
++
++
++The line::
++
++    grubDisplayTest grub.1 defaultindex/0 --default-index
++
++means execute::
++
++    ./grubby --grub --config-file tests/grub.1 --default-index
++
++and compare the output with the file `tests/results/defaultindex/0`.
++
++Writing New Test Cases
++----------------------
++
++To write a new test case for grubby you need a config file which matches the
++initial test conditions (either existing one or a new one), provide a 
++results file (likely a new one) which contains the expected configuration or
++output and finally add a call to the test function(s) using the desired grubby
++parameters in an appropriate section of `test.sh`.
+-- 
+2.17.1
+
diff --git a/SOURCES/0003-Fix-some-stray-whitespace.patch b/SOURCES/0003-Fix-some-stray-whitespace.patch
new file mode 100644
index 0000000..8f72af6
--- /dev/null
+++ b/SOURCES/0003-Fix-some-stray-whitespace.patch
@@ -0,0 +1,35 @@
+From d4b710802da3d780799f1e01e18b613e77b95bb3 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 24 Jun 2015 09:20:35 -0400
+Subject: [PATCH 03/55] Fix some stray whitespace
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ README.rst | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/README.rst b/README.rst
+index a5743ff2f96..754454b7bca 100644
+--- a/README.rst
++++ b/README.rst
+@@ -42,7 +42,7 @@ The invocation syntax is::
+ For example the line::
+ 
+     grubTest grub.1 updargs/g1.1 --update-kernel=DEFAULT --args="root=/dev/hda1"
+-    
++
+ means execute the command::
+ 
+     ./grubby --grub --config-file tests/grub.1 --update-kernel=DEFAULT \
+@@ -66,7 +66,7 @@ Writing New Test Cases
+ ----------------------
+ 
+ To write a new test case for grubby you need a config file which matches the
+-initial test conditions (either existing one or a new one), provide a 
++initial test conditions (either existing one or a new one), provide a
+ results file (likely a new one) which contains the expected configuration or
+ output and finally add a call to the test function(s) using the desired grubby
+ parameters in an appropriate section of `test.sh`.
+-- 
+2.17.1
+
diff --git a/SOURCES/0004-grubby-properly-handle-mixed-and-and-nested-quotes.patch b/SOURCES/0004-grubby-properly-handle-mixed-and-and-nested-quotes.patch
new file mode 100644
index 0000000..4687c26
--- /dev/null
+++ b/SOURCES/0004-grubby-properly-handle-mixed-and-and-nested-quotes.patch
@@ -0,0 +1,162 @@
+From d58e447819e96d84560b16d7632bb7bdf88cc412 Mon Sep 17 00:00:00 2001
+From: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
+Date: Tue, 16 Jun 2015 10:43:21 -0700
+Subject: [PATCH 04/55] grubby: properly handle mixed ' and " and nested quotes
+
+The SLES12 grub2.cfg file on ppc64le by default contains a line like:
+
+  submenu "Bootable snapshot #$snapshot_num" {
+    menuentry "If OK, run 'snapper rollback $snapshot_num' reboot." { true; }
+  }
+
+On any grubby (tested with 8.40) invocation that updates the config
+file, the combination of nested quotes and mixed quotes leads to a
+generated file content like:
+
+  submenu "Bootable snapshot #$snapshot_num" {
+    menuentry 'If OK, run snapper rollback $snapshot_num' rollback $snapshot_num' and reboot." { true; }
+  }
+
+which includes both a change from " to ', but also improperly quoted
+strings and trailing characters relative to the string. This actually
+leads to a failure to boot from the disk by default when using grubby
+(e.g., Autotest) on SLES12 ppc64le. Whether SLES12 should be adding an
+entry like this by default or not is probably open to debate, but grubby
+should be able to hand this input file.
+
+To fix the issue, three changes were necessary:
+
+1) grub2ExtractTitle needs to check that if the second element starts
+with a quote, that the matching element found ends with the same
+quote-type (' vs. ")
+
+2) lineWrite needs to output the right kind of quote based upon if the
+string to be outputted itself contains quotes. This is not currently
+possible in the code, because quotes are stripped out normally by
+readConfig, but with the change in 3), that only happens now for the
+quotes that actually delineate a string.
+
+3) readConfig needs to check that when it is extracting titles and
+determining extras, it uses matching quotes.
+
+With these changes, a simple grubby --set-default=SLES12 (for example),
+now produces:
+
+   submenu "Bootable snapshot #$snapshot_num" {
+     menuentry "If OK, run 'snapper rollback $snapshot_num' and reboot." { true; }
+   }
+
+as expected.
+
+Signed-off-by: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
+---
+ grubby.c | 42 +++++++++++++++++++++++++++++++++---------
+ 1 file changed, 33 insertions(+), 9 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 53fe9250e27..440c6277935 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -451,6 +451,8 @@ char *grub2ExtractTitle(struct singleLine * line) {
+      * whose last character is also quote (assuming it's the closing one) */
+     int resultMaxSize;
+     char * result;
++    /* need to ensure that ' does not match " as we search */
++    char quote_char = *current;
+     
+     resultMaxSize = sizeOfSingleLine(line);
+     result = malloc(resultMaxSize);
+@@ -464,7 +466,7 @@ char *grub2ExtractTitle(struct singleLine * line) {
+ 	current_indent_len = strlen(current_indent);
+ 
+ 	strncat(result, current_indent, current_indent_len);
+-	if (!isquote(current[current_len-1])) {
++	if (current[current_len-1] != quote_char) {
+ 	    strncat(result, current, current_len);
+ 	} else {
+ 	    strncat(result, current, current_len - 1);
+@@ -928,10 +930,23 @@ static int lineWrite(FILE * out, struct singleLine * line,
+ 	/* Need to handle this, because we strip the quotes from
+ 	 * menuentry when read it. */
+ 	if (line->type == LT_MENUENTRY && i == 1) {
+-	    if(!isquote(*line->elements[i].item))
+-		fprintf(out, "\'%s\'", line->elements[i].item);
+-	    else
++	    if(!isquote(*line->elements[i].item)) {
++		int substring = 0;
++		/* If the line contains nested quotes, we did not strip
++		 * the "interna" quotes and we must use the right quotes
++		 * again when writing the updated file. */
++		for (int j = i; j < line->numElements; j++) {
++		    if (strchr(line->elements[i].item, '\'') != NULL) {
++		       substring = 1;
++		       fprintf(out, "\"%s\"", line->elements[i].item);
++		       break;
++		    }
++		}
++		if (!substring)
++		    fprintf(out, "\'%s\'", line->elements[i].item);
++	    } else {
+ 		fprintf(out, "%s", line->elements[i].item);
++	    }
+ 	    fprintf(out, "%s", line->elements[i].indent);
+ 
+ 	    continue;
+@@ -1267,6 +1282,8 @@ static struct grubConfig * readConfig(const char * inName,
+ 	    len = 0;
+ 	    char *extras;
+ 	    char *title;
++	    /* initially unseen value */
++	    char quote_char = '\0';
+ 
+ 	    for (int i = 1; i < line->numElements; i++) {
+ 		len += strlen(line->elements[i].item);
+@@ -1283,13 +1300,16 @@ static struct grubConfig * readConfig(const char * inName,
+ 	    for (int i = 0; i < line->numElements; i++) {
+ 		if (!strcmp(line->elements[i].item, "menuentry"))
+ 		    continue;
+-		if (isquote(*line->elements[i].item))
++		if (isquote(*line->elements[i].item) && quote_char == '\0') {
++		    /* ensure we properly pair off quotes */
++		    quote_char = *line->elements[i].item;
+ 		    title = line->elements[i].item + 1;
+-		else
++		} else {
+ 		    title = line->elements[i].item;
++		}
+ 
+ 		len = strlen(title);
+-	        if (isquote(title[len-1])) {
++	        if (title[len-1] == quote_char) {
+ 		    strncat(buf, title,len-1);
+ 		    break;
+ 		} else {
+@@ -1300,6 +1320,7 @@ static struct grubConfig * readConfig(const char * inName,
+ 
+ 	    /* get extras */
+ 	    int count = 0;
++	    quote_char = '\0';
+ 	    for (int i = 0; i < line->numElements; i++) {
+ 		if (count >= 2) {
+ 		    strcat(extras, line->elements[i].item);
+@@ -1310,12 +1331,15 @@ static struct grubConfig * readConfig(const char * inName,
+ 		    continue;
+ 
+ 		/* count ' or ", there should be two in menuentry line. */
+-		if (isquote(*line->elements[i].item))
++		if (isquote(*line->elements[i].item) && quote_char == '\0') {
++		    /* ensure we properly pair off quotes */
++	            quote_char = *line->elements[i].item;
+ 		    count++;
++		}
+ 
+ 		len = strlen(line->elements[i].item);
+ 
+-		if (isquote(line->elements[i].item[len -1]))
++		if (line->elements[i].item[len -1] == quote_char)
+ 		    count++;
+ 
+ 		/* ok, we get the final ' or ", others are extras. */
+-- 
+2.17.1
+
diff --git a/SOURCES/0005-Don-t-put-spaces-in-debug-entries-on-zipl-platforms.patch b/SOURCES/0005-Don-t-put-spaces-in-debug-entries-on-zipl-platforms.patch
new file mode 100644
index 0000000..d7c7de5
--- /dev/null
+++ b/SOURCES/0005-Don-t-put-spaces-in-debug-entries-on-zipl-platforms.patch
@@ -0,0 +1,34 @@
+From 9659e65a9f7ccc2549b75262a4af50ed99cc4bb9 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 11 Nov 2014 10:46:08 -0500
+Subject: [PATCH 05/55] Don't put spaces in debug entries on zipl platforms.
+
+Because of course zipl can't handle spaces.
+
+Related: rhbz#1152152
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ new-kernel-pkg | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index b634388a83f..1cdbbb99501 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -140,7 +140,11 @@ rungrubby() {
+ 	if [ "$1" == "--debug" ]; then
+ 		[ "$MAKEDEBUG" != "yes" ] && return 0
+ 		[ -n "$verbose" ] && echo "- First, making a debug entry."
+-		declare -x debugtitle=" with debugging"
++		if [ $ARCH = 's390' -o $ARCH = 's390x' ]; then
++			declare -x debugtitle="_with_debugging"
++		else
++			declare -x debugtitle=" with debugging"
++		fi
+ 		declare -x debugargs="$DEBUGARG"
+ 		shift
+ 	else
+-- 
+2.17.1
+
diff --git a/SOURCES/0006-Drop-SEGV-handler.patch b/SOURCES/0006-Drop-SEGV-handler.patch
new file mode 100644
index 0000000..c9e9534
--- /dev/null
+++ b/SOURCES/0006-Drop-SEGV-handler.patch
@@ -0,0 +1,52 @@
+From d9600e2dd1b35a6e74494c8c98ba399d06685041 Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Thu, 27 Feb 2014 10:35:59 +0100
+Subject: [PATCH 06/55] Drop SEGV handler
+
+The generated tracebacks are mostly useless without debuginfo (which is likely
+not present if the crash is not anticipated) and prevent ABRT from doing a
+better job.
+
+Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
+---
+ grubby.c | 17 -----------------
+ 1 file changed, 17 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 440c6277935..649597ed92b 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -4211,21 +4211,6 @@ int addNewKernel(struct grubConfig * config, struct singleEntry * template,
+     return 0;
+ }
+ 
+-static void traceback(int signum)
+-{
+-    void *array[40];
+-    size_t size;
+-
+-    signal(SIGSEGV, SIG_DFL);
+-    memset(array, '\0', sizeof (array));
+-    size = backtrace(array, 40);
+-
+-    fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
+-            (unsigned long)size);
+-    backtrace_symbols_fd(array, size, STDERR_FILENO);
+-    exit(1);
+-}
+-
+ int main(int argc, const char ** argv) {
+     poptContext optCon;
+     const char * grubConfig = NULL;
+@@ -4368,8 +4353,6 @@ int main(int argc, const char ** argv) {
+ 
+     useextlinuxmenu=0;
+ 
+-    signal(SIGSEGV, traceback);
+-
+     int i = 0;
+     for (int j = 1; j < argc; j++)
+ 	i += strlen(argv[j]) + 1;
+-- 
+2.17.1
+
diff --git a/SOURCES/0007-Add-a-bunch-of-tests-for-various-default-kernel-titl.patch b/SOURCES/0007-Add-a-bunch-of-tests-for-various-default-kernel-titl.patch
new file mode 100644
index 0000000..d06773b
--- /dev/null
+++ b/SOURCES/0007-Add-a-bunch-of-tests-for-various-default-kernel-titl.patch
@@ -0,0 +1,183 @@
+From 1da1f577419e85a4e2d717b73af67b79382ad93e Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 2 Jul 2015 12:34:30 -0400
+Subject: [PATCH 07/55] Add a bunch of tests for various
+ --default-{kernel,title,index}.
+
+... and fix some failures where we see them.
+
+Related: rhbz#1184014
+
+(though I can't actually replicate his failure.)
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c                        | 52 ++++++++++++++++++++-------------
+ test.sh                         | 10 +++++++
+ test/results/defaultkernel/g.1  |  1 +
+ test/results/defaultkernel/l1.1 |  1 +
+ test/results/defaultkernel/z.1  |  1 +
+ test/results/defaulttitle/z.1   |  1 +
+ 6 files changed, 45 insertions(+), 21 deletions(-)
+ create mode 100644 test/results/defaultkernel/g.1
+ create mode 100644 test/results/defaultkernel/l1.1
+ create mode 100644 test/results/defaultkernel/z.1
+ create mode 100644 test/results/defaulttitle/z.1
+
+diff --git a/grubby.c b/grubby.c
+index 649597ed92b..0bb486967bf 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -428,7 +428,7 @@ char *grub2ExtractTitle(struct singleLine * line) {
+ 
+     /* bail out if line does not start with menuentry */
+     if (strcmp(line->elements[0].item, "menuentry"))
+-      return NULL;
++	return NULL;
+ 
+     i = 1;
+     current = line->elements[i].item;
+@@ -437,10 +437,12 @@ char *grub2ExtractTitle(struct singleLine * line) {
+     /* if second word is quoted, strip the quotes and return single word */
+     if (isquote(*current) && isquote(current[current_len - 1])) {
+ 	char *tmp;
+-	
+-	tmp = strdup(current);
+-	*(tmp + current_len - 1) = '\0';
+-	return ++tmp;
++
++	tmp = strdup(current+1);
++	if (!tmp)
++	    return NULL;
++	tmp[strlen(tmp)-1] = '\0';
++	return tmp;
+     }
+ 
+     /* if no quotes, return second word verbatim */
+@@ -453,11 +455,11 @@ char *grub2ExtractTitle(struct singleLine * line) {
+     char * result;
+     /* need to ensure that ' does not match " as we search */
+     char quote_char = *current;
+-    
++
+     resultMaxSize = sizeOfSingleLine(line);
+     result = malloc(resultMaxSize);
+     snprintf(result, resultMaxSize, "%s", ++current);
+-    
++
+     i++;
+     for (; i < line->numElements; ++i) {
+ 	current = line->elements[i].item;
+@@ -4648,27 +4650,35 @@ int main(int argc, const char ** argv) {
+ 	struct singleLine * line;
+ 	struct singleEntry * entry;
+ 
+-	if (config->defaultImage == -1) return 0;
++	if (config->defaultImage == -1)
++	    return 0;
+ 	if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
+ 		cfi->defaultIsSaved)
+ 	    config->defaultImage = 0;
+ 	entry = findEntryByIndex(config, config->defaultImage);
+-	if (!entry) return 0;
++	if (!entry)
++		return 0;
+ 
+ 	if (!configureGrub2) {
+-	  line = getLineByType(LT_TITLE, entry->lines);
+-	  if (!line) return 0;
+-	  printf("%s\n", line->elements[1].item);
+-
+-	} else {
+-	  char * title;
+-
+-	  dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
+-	  line = getLineByType(LT_MENUENTRY, entry->lines);
+-	  if (!line) return 0;
+-	  title = grub2ExtractTitle(line);
+-	  if (title)
++	    char *title;
++	    line = getLineByType(LT_TITLE, entry->lines);
++	    if (!line)
++		return 0;
++	    title = extractTitle(config, line);
++	    if (!title)
++		return 0;
+ 	    printf("%s\n", title);
++	    free(title);
++	} else {
++	    char * title;
++
++	    dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
++	    line = getLineByType(LT_MENUENTRY, entry->lines);
++	    if (!line)
++		return 0;
++	    title = grub2ExtractTitle(line);
++	    if (title)
++		printf("%s\n", title);
+ 	}
+ 	return 0;
+ 
+diff --git a/test.sh b/test.sh
+index 6379698c6de..96e0087b1e2 100755
+--- a/test.sh
++++ b/test.sh
+@@ -298,6 +298,9 @@ grubDisplayTest grub.9 defaulttitle/g.9 --default-title
+ grubDisplayTest grub.10 defaulttitle/g.10 --default-title
+ grubDisplayTest grub.11 defaulttitle/g.11 --default-title
+ 
++testing="GRUB display default kernel"
++grubDisplayTest grub.1 defaultkernel/g.1 --default-kernel
++
+ testing="LILO default directive"
+ liloTest lilo.1 default/l1.1 --set-default=/boot/vmlinuz-2.4.18-4
+ liloTest lilo.1 default/l1.2 --remove-kernel=/boot/vmlinuz-2.4.18-4smp
+@@ -305,10 +308,17 @@ liloTest lilo.1 default/l1.3 --add-kernel /boot/kernel --title label \
+     --copy-default
+ liloTest lilo.1 default/l1.4 --add-kernel /boot/kernel --title label \
+     --copy-default --make-default
++liloDisplayTest lilo.1 defaultkernel/l1.1 --default-kernel
+ 
+ testing="Z/IPL default directive"
+ ziplTest zipl.1 default/z1.1 --add-kernel /boot/new-kernel --title test
+ ziplTest zipl.1 default/z1.2 --add-kernel /boot/new-kernel --title test --make-default
++testing="Z/IPL display default index"
++ziplDisplayTest zipl.1 defaultindex/0 --default-index
++testing="Z/IPL display default title"
++ziplDisplayTest zipl.1 defaulttitle/z.1 --default-title
++testing="Z/IPL display default kernel"
++ziplDisplayTest zipl.1 defaultkernel/z.1 --default-kernel
+ 
+ testing="GRUB fallback directive"
+ grubTest grub.5 fallback/g5.1 --remove-kernel=/boot/vmlinuz-2.4.7-ac3 \
+diff --git a/test/results/defaultkernel/g.1 b/test/results/defaultkernel/g.1
+new file mode 100644
+index 00000000000..2c3ac11ead6
+--- /dev/null
++++ b/test/results/defaultkernel/g.1
+@@ -0,0 +1 @@
++/boot/vmlinuz-2.4.7-2
+diff --git a/test/results/defaultkernel/l1.1 b/test/results/defaultkernel/l1.1
+new file mode 100644
+index 00000000000..fd22b1be2b9
+--- /dev/null
++++ b/test/results/defaultkernel/l1.1
+@@ -0,0 +1 @@
++/boot/vmlinuz-2.4.18-4smp
+diff --git a/test/results/defaultkernel/z.1 b/test/results/defaultkernel/z.1
+new file mode 100644
+index 00000000000..2c62e98d4d9
+--- /dev/null
++++ b/test/results/defaultkernel/z.1
+@@ -0,0 +1 @@
++/boot/vmlinuz-2.4.9-37
+diff --git a/test/results/defaulttitle/z.1 b/test/results/defaulttitle/z.1
+new file mode 100644
+index 00000000000..a08e1f35eb7
+--- /dev/null
++++ b/test/results/defaulttitle/z.1
+@@ -0,0 +1 @@
++linux
+-- 
+2.17.1
+
diff --git a/SOURCES/0008-Emit-better-systemd-debug-settings-on-debug-entries.patch b/SOURCES/0008-Emit-better-systemd-debug-settings-on-debug-entries.patch
new file mode 100644
index 0000000..6ec856f
--- /dev/null
+++ b/SOURCES/0008-Emit-better-systemd-debug-settings-on-debug-entries.patch
@@ -0,0 +1,28 @@
+From 5de1b279749f02a126932f9e03ac62706efde699 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 2 Jul 2015 12:44:51 -0400
+Subject: [PATCH 08/55] Emit better systemd debug settings on debug entries.
+
+Resolves: rhbz#1212128
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ new-kernel-pkg | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index 1cdbbb99501..1f6ab39499f 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -121,7 +121,7 @@ mbkernel="$HYPERVISOR"
+ mbargs="$HYPERVISOR_ARGS"
+ adddracutargs=""
+ addplymouthinitrd=""
+-DEBUGARG="systemd.debug"
++DEBUGARG="systemd.log_level=debug systemd.log_target=kmsg"
+ 
+ usage() {
+     echo "Usage: `basename $0` [-v] [--mkinitrd] [--rminitrd] [--dracut]" >&2
+-- 
+2.17.1
+
diff --git a/SOURCES/0009-Add-a-new-makefile-target-that-does-everything-neede.patch b/SOURCES/0009-Add-a-new-makefile-target-that-does-everything-neede.patch
new file mode 100644
index 0000000..561ccce
--- /dev/null
+++ b/SOURCES/0009-Add-a-new-makefile-target-that-does-everything-neede.patch
@@ -0,0 +1,25 @@
+From 80e43f6b8c8316075d8f9f6553ad271e168060b1 Mon Sep 17 00:00:00 2001
+From: Chris Lumens <clumens@redhat.com>
+Date: Wed, 22 Jul 2015 09:13:11 -0400
+Subject: [PATCH 09/55] Add a new makefile target that does everything needed
+ for jenkins.
+
+We should have as much of the logic of how the CI tests are run in source
+control as possible, so that's what this target is for.  Besides this, jenkins
+just runs a "git clean" first.
+---
+ Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Makefile b/Makefile
+index ac144046133..ade4421aa25 100644
+--- a/Makefile
++++ b/Makefile
+@@ -84,3 +84,4 @@ archive:
+ upload: archive
+ 	@scp grubby-$(VERSION).tar.bz2 fedorahosted.org:grubby
+ 
++ci: test
+-- 
+2.17.1
+
diff --git a/SOURCES/0010-Make-the-grub1-defaultkernel-test-more-reliable.patch b/SOURCES/0010-Make-the-grub1-defaultkernel-test-more-reliable.patch
new file mode 100644
index 0000000..41d6b24
--- /dev/null
+++ b/SOURCES/0010-Make-the-grub1-defaultkernel-test-more-reliable.patch
@@ -0,0 +1,41 @@
+From ec969de50ea5fa31d98cd00afa6a3f8a43e606a4 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 2 Jul 2015 14:30:09 -0400
+Subject: [PATCH 10/55] Make the grub1 "defaultkernel" test more reliable.
+
+Basically just do it twice with various incarnations of
+--boot-filesystem={/,/boot}
+
+Related: rhbz#1184014
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ test.sh                        | 3 ++-
+ test/results/defaultkernel/g.2 | 1 +
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+ create mode 100644 test/results/defaultkernel/g.2
+
+diff --git a/test.sh b/test.sh
+index 96e0087b1e2..2985fd62bf9 100755
+--- a/test.sh
++++ b/test.sh
+@@ -299,7 +299,8 @@ grubDisplayTest grub.10 defaulttitle/g.10 --default-title
+ grubDisplayTest grub.11 defaulttitle/g.11 --default-title
+ 
+ testing="GRUB display default kernel"
+-grubDisplayTest grub.1 defaultkernel/g.1 --default-kernel
++grubDisplayTest grub.1 defaultkernel/g.1 --boot-filesystem=/boot --default-kernel
++grubDisplayTest grub.1 defaultkernel/g.2 --boot-filesystem=/ --default-kernel
+ 
+ testing="LILO default directive"
+ liloTest lilo.1 default/l1.1 --set-default=/boot/vmlinuz-2.4.18-4
+diff --git a/test/results/defaultkernel/g.2 b/test/results/defaultkernel/g.2
+new file mode 100644
+index 00000000000..d15855e1b57
+--- /dev/null
++++ b/test/results/defaultkernel/g.2
+@@ -0,0 +1 @@
++/vmlinuz-2.4.7-2
+-- 
+2.17.1
+
diff --git a/SOURCES/0011-Don-t-leak-from-one-extractTitle-call.patch b/SOURCES/0011-Don-t-leak-from-one-extractTitle-call.patch
new file mode 100644
index 0000000..ab32170
--- /dev/null
+++ b/SOURCES/0011-Don-t-leak-from-one-extractTitle-call.patch
@@ -0,0 +1,85 @@
+From 38d8178482ea7dabf7c4ab8c2973faa2b469e9c7 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 2 Jul 2015 16:26:59 -0400
+Subject: [PATCH 11/55] Don't leak from one extractTitle() call.
+
+Found by coverity.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 0bb486967bf..70477ba14ee 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -1510,13 +1510,14 @@ static struct grubConfig * readConfig(const char * inName,
+     return cfg;
+ }
+ 
+-static void writeDefault(FILE * out, char * indent, 
++static void writeDefault(FILE * out, char * indent,
+ 			 char * separator, struct grubConfig * cfg) {
+     struct singleEntry * entry;
+     struct singleLine * line;
+     int i;
+ 
+-    if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT) return;
++    if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT)
++	return;
+ 
+     if (cfg->defaultImage == DEFAULT_SAVED)
+ 	fprintf(out, "%sdefault%ssaved\n", indent, separator);
+@@ -1540,34 +1541,40 @@ static void writeDefault(FILE * out, char * indent,
+ 	        fprintf(out, "%sset default=\"%d\"\n", indent,
+ 			cfg->defaultImage);
+ 	    } else {
+-		fprintf(out, "%sdefault%s%d\n", indent, separator, 
++		fprintf(out, "%sdefault%s%d\n", indent, separator,
+ 			cfg->defaultImage);
+ 	    }
+ 	} else {
+ 	    int image = cfg->defaultImage;
+ 
+ 	    entry = cfg->entries;
+-	    while (entry && entry->skip) entry = entry->next;
++	    while (entry && entry->skip)
++		entry = entry->next;
+ 
+ 	    i = 0;
+ 	    while (entry && i < image) {
+ 		entry = entry->next;
+ 
+-		while (entry && entry->skip) entry = entry->next;
++		while (entry && entry->skip)
++		    entry = entry->next;
+ 		i++;
+ 	    }
+ 
+-	    if (!entry) return;
++	    if (!entry)
++		return;
+ 
+ 	    line = getLineByType(LT_TITLE, entry->lines);
+ 
+ 	    if (line && line->numElements >= 2)
+-		fprintf(out, "%sdefault%s%s\n", indent, separator, 
++		fprintf(out, "%sdefault%s%s\n", indent, separator,
+ 			line->elements[1].item);
+-            else if (line && (line->numElements == 1) && 
++            else if (line && (line->numElements == 1) &&
+                      cfg->cfi->titleBracketed) {
+-		fprintf(out, "%sdefault%s%s\n", indent, separator, 
+-                        extractTitle(cfg, line));
++		char *title = extractTitle(cfg, line);
++		if (title) {
++		    fprintf(out, "%sdefault%s%s\n", indent, separator, title);
++		    free(title);
++		}
+             }
+ 	}
+     }
+-- 
+2.17.1
+
diff --git a/SOURCES/0012-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch b/SOURCES/0012-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch
new file mode 100644
index 0000000..fc23e78
--- /dev/null
+++ b/SOURCES/0012-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch
@@ -0,0 +1,42 @@
+From 3a0171fd435765161406238c8df6f66e859ddd93 Mon Sep 17 00:00:00 2001
+From: Don Zickus <dzickus@redhat.com>
+Date: Wed, 22 Jul 2015 13:58:53 -0400
+Subject: [PATCH 12/55] ppc64le sync grub.cfg changes to disk (#1212114)
+
+After installing a new kernel, if a panic is induced, not all the kernel
+pieces are on the disk (most importantly the grub.cfg changes).  This can
+lead to a hung system on a reboot because the older kernel can not be found.
+
+Address this by forcing all the changes (mainly the fs meta data) to disk
+before finishing the kernel package installation.
+
+Tested by 'yum install kernel-...; echo c > /proc/sysrq-trigger'.
+
+Before, the machine would panic and on reboot be stuck without a grub.cfg
+to read.  After, works as expected.
+
+Resolves: rhbz#1212114
+---
+ new-kernel-pkg | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index 1f6ab39499f..90652da06b7 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -927,4 +927,12 @@ fi
+ # if we mounted the U-Boot directory, unmount it.
+ [ -n "$mounted" ] && umount $ubootDir
+ 
++# make sure changes make it to the disk.
++# if /boot is a mountpoint, force the meta data on disk
++# to by-pass writeback delay.
++# PPC64LE-only to deal with Petitboot issues
++if [ "$ARCH" = "ppc64le" ]; then
++    sync && mountpoint -q /boot &&fsfreeze -f /boot && fsfreeze -u /boot
++fi
++
+ exit 0
+-- 
+2.17.1
+
diff --git a/SOURCES/0013-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch b/SOURCES/0013-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch
new file mode 100644
index 0000000..4e2136d
--- /dev/null
+++ b/SOURCES/0013-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch
@@ -0,0 +1,38 @@
+From 92adaf4e655c3e6833e6f3b96fe1f5b75f75fd64 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 6 Aug 2015 10:06:13 -0400
+Subject: [PATCH 13/55] Make it possible to run "test.sh --verbose" from the
+ make command line.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index ade4421aa25..cc7e823959f 100644
+--- a/Makefile
++++ b/Makefile
+@@ -26,6 +26,10 @@ CC = gcc
+ RPM_OPT_FLAGS ?= -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector
+ CFLAGS += $(RPM_OPT_FLAGS) -std=gnu99 -Wall -Werror -Wno-error=unused-function -Wno-unused-function -ggdb
+ LDFLAGS := 
++VERBOSE_TEST :=
++ifneq ($(VERBOSE_TEST),)
++	VERBOSE_TEST="--verbose"
++endif
+ 
+ grubby_LIBS = -lblkid -lpopt
+ 
+@@ -39,7 +43,7 @@ debug : clean
+ 
+ test: all
+ 	@export TOPDIR=$(TOPDIR)
+-	@./test.sh
++	@./test.sh $(VERBOSE_TEST)
+ 
+ install: all
+ 	mkdir -p $(DESTDIR)$(PREFIX)/sbin
+-- 
+2.17.1
+
diff --git a/SOURCES/0014-Lindent-dammit.patch b/SOURCES/0014-Lindent-dammit.patch
new file mode 100644
index 0000000..9d14e44
--- /dev/null
+++ b/SOURCES/0014-Lindent-dammit.patch
@@ -0,0 +1,9239 @@
+From 446e0e6f0179373ccb2073df62d5552c44a0f36a Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 18 Aug 2015 10:43:39 -0400
+Subject: [PATCH 14/55] Lindent, dammit.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c | 8666 ++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 4560 insertions(+), 4106 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 70477ba14ee..fe6595b8386 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -48,7 +48,7 @@
+ #define dbgPrintf(format, args...)
+ #endif
+ 
+-int debug = 0;	/* Currently just for template debugging */
++int debug = 0;			/* Currently just for template debugging */
+ 
+ #define _(A) (A)
+ 
+@@ -70,51 +70,51 @@ char *saved_command_line = NULL;
+ 
+ /* comments get lumped in with indention */
+ struct lineElement {
+-    char * item;
+-    char * indent;
++	char *item;
++	char *indent;
+ };
+ 
+-enum lineType_e { 
+-    LT_WHITESPACE   = 1 << 0,
+-    LT_TITLE        = 1 << 1,
+-    LT_KERNEL       = 1 << 2,
+-    LT_INITRD       = 1 << 3,
+-    LT_HYPER        = 1 << 4,
+-    LT_DEFAULT      = 1 << 5,
+-    LT_MBMODULE     = 1 << 6,
+-    LT_ROOT         = 1 << 7,
+-    LT_FALLBACK     = 1 << 8,
+-    LT_KERNELARGS   = 1 << 9,
+-    LT_BOOT         = 1 << 10,
+-    LT_BOOTROOT     = 1 << 11,
+-    LT_LBA          = 1 << 12,
+-    LT_OTHER        = 1 << 13,
+-    LT_GENERIC      = 1 << 14,
+-    LT_ECHO	    = 1 << 16,
+-    LT_MENUENTRY    = 1 << 17,
+-    LT_ENTRY_END    = 1 << 18,
+-    LT_SET_VARIABLE = 1 << 19,
+-    LT_KERNEL_EFI   = 1 << 20,
+-    LT_INITRD_EFI   = 1 << 21,
+-    LT_KERNEL_16    = 1 << 22,
+-    LT_INITRD_16    = 1 << 23,
+-    LT_DEVTREE      = 1 << 24,
+-    LT_UNKNOWN      = 1 << 25,
++enum lineType_e {
++	LT_WHITESPACE = 1 << 0,
++	LT_TITLE = 1 << 1,
++	LT_KERNEL = 1 << 2,
++	LT_INITRD = 1 << 3,
++	LT_HYPER = 1 << 4,
++	LT_DEFAULT = 1 << 5,
++	LT_MBMODULE = 1 << 6,
++	LT_ROOT = 1 << 7,
++	LT_FALLBACK = 1 << 8,
++	LT_KERNELARGS = 1 << 9,
++	LT_BOOT = 1 << 10,
++	LT_BOOTROOT = 1 << 11,
++	LT_LBA = 1 << 12,
++	LT_OTHER = 1 << 13,
++	LT_GENERIC = 1 << 14,
++	LT_ECHO = 1 << 16,
++	LT_MENUENTRY = 1 << 17,
++	LT_ENTRY_END = 1 << 18,
++	LT_SET_VARIABLE = 1 << 19,
++	LT_KERNEL_EFI = 1 << 20,
++	LT_INITRD_EFI = 1 << 21,
++	LT_KERNEL_16 = 1 << 22,
++	LT_INITRD_16 = 1 << 23,
++	LT_DEVTREE = 1 << 24,
++	LT_UNKNOWN = 1 << 25,
+ };
+ 
+ struct singleLine {
+-    char * indent;
+-    int numElements;
+-    struct lineElement * elements;
+-    struct singleLine * next;
+-    enum lineType_e type;
++	char *indent;
++	int numElements;
++	struct lineElement *elements;
++	struct singleLine *next;
++	enum lineType_e type;
+ };
+ 
+ struct singleEntry {
+-    struct singleLine * lines;
+-    int skip;
+-    int multiboot;
+-    struct singleEntry * next;
++	struct singleLine *lines;
++	int skip;
++	int multiboot;
++	struct singleEntry *next;
+ };
+ 
+ #define GRUBBY_BADIMAGE_OKAY	(1 << 0)
+@@ -135,1723 +135,1849 @@ struct singleEntry {
+ #define DEFAULT_SAVED_GRUB2 -3
+ 
+ struct keywordTypes {
+-    char * key;
+-    enum lineType_e type;
+-    char nextChar;
+-    char separatorChar;
++	char *key;
++	enum lineType_e type;
++	char nextChar;
++	char separatorChar;
+ };
+ 
+ struct configFileInfo;
+ 
+-typedef const char *(*findConfigFunc)(struct configFileInfo *);
+-typedef const int (*writeLineFunc)(struct configFileInfo *,
+-				struct singleLine *line);
+-typedef char *(*getEnvFunc)(struct configFileInfo *, char *name);
+-typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value);
++typedef const char *(*findConfigFunc) (struct configFileInfo *);
++typedef const int (*writeLineFunc) (struct configFileInfo *,
++				    struct singleLine * line);
++typedef char *(*getEnvFunc) (struct configFileInfo *, char *name);
++typedef int (*setEnvFunc) (struct configFileInfo *, char *name, char *value);
+ 
+ struct configFileInfo {
+-    char * defaultConfig;
+-    findConfigFunc findConfig;
+-    writeLineFunc writeLine;
+-    getEnvFunc getEnv;
+-    setEnvFunc setEnv;
+-    struct keywordTypes * keywords;
+-    int caseInsensitive;
+-    int defaultIsIndex;
+-    int defaultIsVariable;
+-    int defaultSupportSaved;
+-    int defaultIsSaved;
+-    int defaultIsUnquoted;
+-    enum lineType_e entryStart;
+-    enum lineType_e entryEnd;
+-    int needsBootPrefix;
+-    int argsInQuotes;
+-    int maxTitleLength;
+-    int titleBracketed;
+-    int titlePosition;
+-    int mbHyperFirst;
+-    int mbInitRdIsModule;
+-    int mbConcatArgs;
+-    int mbAllowExtraInitRds;
+-    char *envFile;
++	char *defaultConfig;
++	findConfigFunc findConfig;
++	writeLineFunc writeLine;
++	getEnvFunc getEnv;
++	setEnvFunc setEnv;
++	struct keywordTypes *keywords;
++	int caseInsensitive;
++	int defaultIsIndex;
++	int defaultIsVariable;
++	int defaultSupportSaved;
++	int defaultIsSaved;
++	int defaultIsUnquoted;
++	enum lineType_e entryStart;
++	enum lineType_e entryEnd;
++	int needsBootPrefix;
++	int argsInQuotes;
++	int maxTitleLength;
++	int titleBracketed;
++	int titlePosition;
++	int mbHyperFirst;
++	int mbInitRdIsModule;
++	int mbConcatArgs;
++	int mbAllowExtraInitRds;
++	char *envFile;
+ };
+ 
+ struct keywordTypes grubKeywords[] = {
+-    { "title",	    LT_TITLE,	    ' ' },
+-    { "root",	    LT_BOOTROOT,    ' ' },
+-    { "default",    LT_DEFAULT,	    ' ' },
+-    { "fallback",   LT_FALLBACK,    ' ' },
+-    { "kernel",	    LT_KERNEL,	    ' ' },
+-    { "initrd",	    LT_INITRD,	    ' ',	' ' },
+-    { "module",     LT_MBMODULE,    ' ' },
+-    { "kernel",     LT_HYPER,       ' ' },
+-    { NULL,	    0, 0 },
++	{"title", LT_TITLE, ' '},
++	{"root", LT_BOOTROOT, ' '},
++	{"default", LT_DEFAULT, ' '},
++	{"fallback", LT_FALLBACK, ' '},
++	{"kernel", LT_KERNEL, ' '},
++	{"initrd", LT_INITRD, ' ', ' '},
++	{"module", LT_MBMODULE, ' '},
++	{"kernel", LT_HYPER, ' '},
++	{NULL, 0, 0},
+ };
+ 
+-const char *grubFindConfig(struct configFileInfo *cfi) {
+-    static const char *configFiles[] = {
+-	"/boot/grub/menu.lst",
+-	"/etc/grub.conf",
+-	NULL
+-    };
+-    static int i = -1;
++const char *grubFindConfig(struct configFileInfo *cfi)
++{
++	static const char *configFiles[] = {
++		"/boot/grub/menu.lst",
++		"/etc/grub.conf",
++		NULL
++	};
++	static int i = -1;
+ 
+-    if (i == -1) {
+-	for (i = 0; configFiles[i] != NULL; i++) {
+-	    dbgPrintf("Checking \"%s\": ", configFiles[i]);
+-	    if (!access(configFiles[i], R_OK)) {
+-		dbgPrintf("found\n");
+-		return configFiles[i];
+-	    }
+-	    dbgPrintf("not found\n");
++	if (i == -1) {
++		for (i = 0; configFiles[i] != NULL; i++) {
++			dbgPrintf("Checking \"%s\": ", configFiles[i]);
++			if (!access(configFiles[i], R_OK)) {
++				dbgPrintf("found\n");
++				return configFiles[i];
++			}
++			dbgPrintf("not found\n");
++		}
+ 	}
+-    }
+-    return configFiles[i];
++	return configFiles[i];
+ }
+ 
+ struct configFileInfo grubConfigType = {
+-    .findConfig = grubFindConfig,
+-    .keywords = grubKeywords,
+-    .defaultIsIndex = 1,
+-    .defaultSupportSaved = 1,
+-    .entryStart = LT_TITLE,
+-    .needsBootPrefix = 1,
+-    .mbHyperFirst = 1,
+-    .mbInitRdIsModule = 1,
+-    .mbAllowExtraInitRds = 1,
+-    .titlePosition = 1,
++	.findConfig = grubFindConfig,
++	.keywords = grubKeywords,
++	.defaultIsIndex = 1,
++	.defaultSupportSaved = 1,
++	.entryStart = LT_TITLE,
++	.needsBootPrefix = 1,
++	.mbHyperFirst = 1,
++	.mbInitRdIsModule = 1,
++	.mbAllowExtraInitRds = 1,
++	.titlePosition = 1,
+ };
+ 
+ struct keywordTypes grub2Keywords[] = {
+-    { "menuentry",  LT_MENUENTRY,   ' ' },
+-    { "}",          LT_ENTRY_END,   ' ' },
+-    { "echo",       LT_ECHO,        ' ' },
+-    { "set",        LT_SET_VARIABLE,' ', '=' },
+-    { "root",       LT_BOOTROOT,    ' ' },
+-    { "default",    LT_DEFAULT,     ' ' },
+-    { "fallback",   LT_FALLBACK,    ' ' },
+-    { "linux",      LT_KERNEL,      ' ' },
+-    { "linuxefi",   LT_KERNEL_EFI,  ' ' },
+-    { "linux16",    LT_KERNEL_16,   ' ' },
+-    { "initrd",     LT_INITRD,      ' ', ' ' },
+-    { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
+-    { "initrd16",   LT_INITRD_16,   ' ', ' ' },
+-    { "module",     LT_MBMODULE,    ' ' },
+-    { "kernel",     LT_HYPER,       ' ' },
+-    { "devicetree", LT_DEVTREE,  ' ' },
+-    { NULL, 0, 0 },
++	{"menuentry", LT_MENUENTRY, ' '},
++	{"}", LT_ENTRY_END, ' '},
++	{"echo", LT_ECHO, ' '},
++	{"set", LT_SET_VARIABLE, ' ', '='},
++	{"root", LT_BOOTROOT, ' '},
++	{"default", LT_DEFAULT, ' '},
++	{"fallback", LT_FALLBACK, ' '},
++	{"linux", LT_KERNEL, ' '},
++	{"linuxefi", LT_KERNEL_EFI, ' '},
++	{"linux16", LT_KERNEL_16, ' '},
++	{"initrd", LT_INITRD, ' ', ' '},
++	{"initrdefi", LT_INITRD_EFI, ' ', ' '},
++	{"initrd16", LT_INITRD_16, ' ', ' '},
++	{"module", LT_MBMODULE, ' '},
++	{"kernel", LT_HYPER, ' '},
++	{"devicetree", LT_DEVTREE, ' '},
++	{NULL, 0, 0},
+ };
+ 
+-const char *grub2FindConfig(struct configFileInfo *cfi) {
+-    static const char *configFiles[] = {
+-	"/etc/grub2-efi.cfg",
+-	"/etc/grub2.cfg",
+-	"/boot/grub2/grub.cfg",
+-	"/boot/grub2-efi/grub.cfg",
+-	NULL
+-    };
+-    static int i = -1;
+-    static const char *grub_cfg = "/boot/grub/grub.cfg";
+-    int rc = -1;
++const char *grub2FindConfig(struct configFileInfo *cfi)
++{
++	static const char *configFiles[] = {
++		"/etc/grub2-efi.cfg",
++		"/etc/grub2.cfg",
++		"/boot/grub2/grub.cfg",
++		"/boot/grub2-efi/grub.cfg",
++		NULL
++	};
++	static int i = -1;
++	static const char *grub_cfg = "/boot/grub/grub.cfg";
++	int rc = -1;
+ 
+-    if (i == -1) {
+-	for (i = 0; configFiles[i] != NULL; i++) {
+-	    dbgPrintf("Checking \"%s\": ", configFiles[i]);
+-	    if ((rc = access(configFiles[i], R_OK))) {
+-		if (errno == EACCES) {
+-		    printf("Unable to access bootloader configuration file "
+-		    	   "\"%s\": %m\n", configFiles[i]);
+-		    exit(1);
++	if (i == -1) {
++		for (i = 0; configFiles[i] != NULL; i++) {
++			dbgPrintf("Checking \"%s\": ", configFiles[i]);
++			if ((rc = access(configFiles[i], R_OK))) {
++				if (errno == EACCES) {
++					printf
++					    ("Unable to access bootloader configuration file "
++					     "\"%s\": %m\n", configFiles[i]);
++					exit(1);
++				}
++				continue;
++			} else {
++				dbgPrintf("found\n");
++				return configFiles[i];
++			}
+ 		}
+-		continue;
+-	    } else {
++	}
++
++	/* Ubuntu renames grub2 to grub, so check for the grub.d directory
++	 * that isn't in grub1, and if it exists, return the config file path
++	 * that they use. */
++	if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
+ 		dbgPrintf("found\n");
+-		return configFiles[i];
+-	    }
++		return grub_cfg;
+ 	}
+-    }
+ 
+-    /* Ubuntu renames grub2 to grub, so check for the grub.d directory
+-     * that isn't in grub1, and if it exists, return the config file path
+-     * that they use. */
+-    if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
+-	dbgPrintf("found\n");
+-	return grub_cfg;
+-    }
+-
+-    dbgPrintf("not found\n");
+-    return configFiles[i];
++	dbgPrintf("not found\n");
++	return configFiles[i];
+ }
+ 
+ /* kind of hacky.  It'll give the first 1024 bytes, ish. */
+ static char *grub2GetEnv(struct configFileInfo *info, char *name)
+ {
+-    static char buf[1025];
+-    char *s = NULL;
+-    char *ret = NULL;
+-    char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
+-    int rc = asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name);
++	static char buf[1025];
++	char *s = NULL;
++	char *ret = NULL;
++	char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
++	int rc =
++	    asprintf(&s, "grub2-editenv %s list | grep '^%s='", envFile, name);
+ 
+-    if (rc < 0)
+-	return NULL;
++	if (rc < 0)
++		return NULL;
+ 
+-    FILE *f = popen(s, "r");
+-    if (!f)
+-	goto out;
++	FILE *f = popen(s, "r");
++	if (!f)
++		goto out;
+ 
+-    memset(buf, '\0', sizeof (buf));
+-    ret = fgets(buf, 1024, f);
+-    pclose(f);
++	memset(buf, '\0', sizeof(buf));
++	ret = fgets(buf, 1024, f);
++	pclose(f);
+ 
+-    if (ret) {
+-	ret += strlen(name) + 1;
+-	ret[strlen(ret) - 1] = '\0';
+-    }
+-    dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
++	if (ret) {
++		ret += strlen(name) + 1;
++		ret[strlen(ret) - 1] = '\0';
++	}
++	dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
+ out:
+-    free(s);
+-    return ret;
++	free(s);
++	return ret;
+ }
+ 
+ static int sPopCount(const char *s, const char *c)
+ {
+-    int ret = 0;
+-    if (!s)
+-	return -1;
+-    for (int i = 0; s[i] != '\0'; i++)
+-	for (int j = 0; c[j] != '\0'; j++)
+-	    if (s[i] == c[j])
+-		ret++;
+-    return ret;
++	int ret = 0;
++	if (!s)
++		return -1;
++	for (int i = 0; s[i] != '\0'; i++)
++		for (int j = 0; c[j] != '\0'; j++)
++			if (s[i] == c[j])
++				ret++;
++	return ret;
+ }
+ 
+ static char *shellEscape(const char *s)
+ {
+-    int l = strlen(s) + sPopCount(s, "'") * 2;
++	int l = strlen(s) + sPopCount(s, "'") * 2;
+ 
+-    char *ret = calloc(l+1, sizeof (*ret));
+-    if (!ret)
+-	return NULL;
+-    for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
+-	if (s[i] == '\'')
+-	    ret[j++] = '\\';
+-	ret[j] = s[i];
+-    }
+-    return ret;
++	char *ret = calloc(l + 1, sizeof(*ret));
++	if (!ret)
++		return NULL;
++	for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
++		if (s[i] == '\'')
++			ret[j++] = '\\';
++		ret[j] = s[i];
++	}
++	return ret;
+ }
+ 
+ static void unquote(char *s)
+ {
+-    int l = strlen(s);
++	int l = strlen(s);
+ 
+-    if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
+-	memmove(s, s+1, l-2);
+-	s[l-2] = '\0';
+-    }
++	if ((s[l - 1] == '\'' && s[0] == '\'')
++	    || (s[l - 1] == '"' && s[0] == '"')) {
++		memmove(s, s + 1, l - 2);
++		s[l - 2] = '\0';
++	}
+ }
+ 
+ static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
+ {
+-    char *s = NULL;
+-    int rc = 0;
+-    char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
++	char *s = NULL;
++	int rc = 0;
++	char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv";
+ 
+-    unquote(value);
+-    value = shellEscape(value);
+-    if (!value)
+-	    return -1;
++	unquote(value);
++	value = shellEscape(value);
++	if (!value)
++		return -1;
+ 
+-    rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value);
+-    free(value);
+-    if (rc <0)
+-	return -1;
++	rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value);
++	free(value);
++	if (rc < 0)
++		return -1;
+ 
+-    dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
+-    rc = system(s);
+-    free(s);
+-    return rc;
++	dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
++	rc = system(s);
++	free(s);
++	return rc;
+ }
+ 
+ /* this is a gigantic hack to avoid clobbering grub2 variables... */
+ static int is_special_grub2_variable(const char *name)
+ {
+-    if (!strcmp(name,"\"${next_entry}\""))
+-	return 1;
+-    if (!strcmp(name,"\"${prev_saved_entry}\""))
+-	return 1;
+-    return 0;
++	if (!strcmp(name, "\"${next_entry}\""))
++		return 1;
++	if (!strcmp(name, "\"${prev_saved_entry}\""))
++		return 1;
++	return 0;
+ }
+ 
+-int sizeOfSingleLine(struct singleLine * line) {
+-  int count = 0;
++int sizeOfSingleLine(struct singleLine *line)
++{
++	int count = 0;
+ 
+-  for (int i = 0; i < line->numElements; i++) {
+-    int indentSize = 0;
++	for (int i = 0; i < line->numElements; i++) {
++		int indentSize = 0;
+ 
+-    count = count + strlen(line->elements[i].item);
++		count = count + strlen(line->elements[i].item);
+ 
+-    indentSize = strlen(line->elements[i].indent);
+-    if (indentSize > 0)
+-      count = count + indentSize;
+-    else
+-      /* be extra safe and add room for whitespaces */
+-      count = count + 1;
+-  }
++		indentSize = strlen(line->elements[i].indent);
++		if (indentSize > 0)
++			count = count + indentSize;
++		else
++			/* be extra safe and add room for whitespaces */
++			count = count + 1;
++	}
+ 
+-  /* room for trailing terminator */
+-  count = count + 1;
++	/* room for trailing terminator */
++	count = count + 1;
+ 
+-  return count;
++	return count;
+ }
+ 
+ static int isquote(char q)
+ {
+-    if (q == '\'' || q == '\"')
+-	return 1;
+-    return 0;
++	if (q == '\'' || q == '\"')
++		return 1;
++	return 0;
+ }
+ 
+-static int iskernel(enum lineType_e type) {
+-    return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
++static int iskernel(enum lineType_e type)
++{
++	return (type == LT_KERNEL || type == LT_KERNEL_EFI
++		|| type == LT_KERNEL_16);
+ }
+ 
+-static int isinitrd(enum lineType_e type) {
+-    return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
++static int isinitrd(enum lineType_e type)
++{
++	return (type == LT_INITRD || type == LT_INITRD_EFI
++		|| type == LT_INITRD_16);
+ }
+ 
+-char *grub2ExtractTitle(struct singleLine * line) {
+-    char * current;
+-    char * current_indent;
+-    int current_len;
+-    int current_indent_len;
+-    int i;
++char *grub2ExtractTitle(struct singleLine *line)
++{
++	char *current;
++	char *current_indent;
++	int current_len;
++	int current_indent_len;
++	int i;
+ 
+-    /* bail out if line does not start with menuentry */
+-    if (strcmp(line->elements[0].item, "menuentry"))
+-	return NULL;
++	/* bail out if line does not start with menuentry */
++	if (strcmp(line->elements[0].item, "menuentry"))
++		return NULL;
+ 
+-    i = 1;
+-    current = line->elements[i].item;
+-    current_len = strlen(current);
+-
+-    /* if second word is quoted, strip the quotes and return single word */
+-    if (isquote(*current) && isquote(current[current_len - 1])) {
+-	char *tmp;
+-
+-	tmp = strdup(current+1);
+-	if (!tmp)
+-	    return NULL;
+-	tmp[strlen(tmp)-1] = '\0';
+-	return tmp;
+-    }
+-
+-    /* if no quotes, return second word verbatim */
+-    if (!isquote(*current))
+-	return current;
+-
+-    /* second element start with a quote, so we have to find the element
+-     * whose last character is also quote (assuming it's the closing one) */
+-    int resultMaxSize;
+-    char * result;
+-    /* need to ensure that ' does not match " as we search */
+-    char quote_char = *current;
+-
+-    resultMaxSize = sizeOfSingleLine(line);
+-    result = malloc(resultMaxSize);
+-    snprintf(result, resultMaxSize, "%s", ++current);
+-
+-    i++;
+-    for (; i < line->numElements; ++i) {
++	i = 1;
+ 	current = line->elements[i].item;
+ 	current_len = strlen(current);
+-	current_indent = line->elements[i].indent;
+-	current_indent_len = strlen(current_indent);
+-
+-	strncat(result, current_indent, current_indent_len);
+-	if (current[current_len-1] != quote_char) {
+-	    strncat(result, current, current_len);
+-	} else {
+-	    strncat(result, current, current_len - 1);
+-	    break;
++
++	/* if second word is quoted, strip the quotes and return single word */
++	if (isquote(*current) && isquote(current[current_len - 1])) {
++		char *tmp;
++
++		tmp = strdup(current + 1);
++		if (!tmp)
++			return NULL;
++		tmp[strlen(tmp) - 1] = '\0';
++		return tmp;
++	}
++
++	/* if no quotes, return second word verbatim */
++	if (!isquote(*current))
++		return current;
++
++	/* second element start with a quote, so we have to find the element
++	 * whose last character is also quote (assuming it's the closing one) */
++	int resultMaxSize;
++	char *result;
++	/* need to ensure that ' does not match " as we search */
++	char quote_char = *current;
++
++	resultMaxSize = sizeOfSingleLine(line);
++	result = malloc(resultMaxSize);
++	snprintf(result, resultMaxSize, "%s", ++current);
++
++	i++;
++	for (; i < line->numElements; ++i) {
++		current = line->elements[i].item;
++		current_len = strlen(current);
++		current_indent = line->elements[i].indent;
++		current_indent_len = strlen(current_indent);
++
++		strncat(result, current_indent, current_indent_len);
++		if (current[current_len - 1] != quote_char) {
++			strncat(result, current, current_len);
++		} else {
++			strncat(result, current, current_len - 1);
++			break;
++		}
+ 	}
+-    }
+-    return result;
++	return result;
+ }
+ 
+ struct configFileInfo grub2ConfigType = {
+-    .findConfig = grub2FindConfig,
+-    .getEnv = grub2GetEnv,
+-    .setEnv = grub2SetEnv,
+-    .keywords = grub2Keywords,
+-    .defaultIsIndex = 1,
+-    .defaultSupportSaved = 1,
+-    .defaultIsVariable = 1,
+-    .entryStart = LT_MENUENTRY,
+-    .entryEnd = LT_ENTRY_END,
+-    .titlePosition = 1,
+-    .needsBootPrefix = 1,
+-    .mbHyperFirst = 1,
+-    .mbInitRdIsModule = 1,
+-    .mbAllowExtraInitRds = 1,
++	.findConfig = grub2FindConfig,
++	.getEnv = grub2GetEnv,
++	.setEnv = grub2SetEnv,
++	.keywords = grub2Keywords,
++	.defaultIsIndex = 1,
++	.defaultSupportSaved = 1,
++	.defaultIsVariable = 1,
++	.entryStart = LT_MENUENTRY,
++	.entryEnd = LT_ENTRY_END,
++	.titlePosition = 1,
++	.needsBootPrefix = 1,
++	.mbHyperFirst = 1,
++	.mbInitRdIsModule = 1,
++	.mbAllowExtraInitRds = 1,
+ };
+ 
+ struct keywordTypes yabootKeywords[] = {
+-    { "label",	    LT_TITLE,	    '=' },
+-    { "root",	    LT_ROOT,	    '=' },
+-    { "default",    LT_DEFAULT,	    '=' },
+-    { "image",	    LT_KERNEL,	    '=' },
+-    { "bsd",	    LT_GENERIC,	    '=' },
+-    { "macos",	    LT_GENERIC,	    '=' },
+-    { "macosx",	    LT_GENERIC,	    '=' },
+-    { "magicboot",  LT_GENERIC,	    '=' },
+-    { "darwin",	    LT_GENERIC,	    '=' },
+-    { "timeout",    LT_GENERIC,	    '=' },
+-    { "install",    LT_GENERIC,	    '=' },
+-    { "fstype",	    LT_GENERIC,	    '=' },
+-    { "hfstype",    LT_GENERIC,	    '=' },
+-    { "delay",	    LT_GENERIC,	    '=' },
+-    { "defaultos",  LT_GENERIC,     '=' },
+-    { "init-message", LT_GENERIC,   '=' },
+-    { "enablecdboot", LT_GENERIC,   ' ' },
+-    { "enableofboot", LT_GENERIC,   ' ' },
+-    { "enablenetboot", LT_GENERIC,  ' ' },
+-    { "nonvram",    LT_GENERIC,	    ' ' },
+-    { "hide",	    LT_GENERIC,	    ' ' },
+-    { "protect",    LT_GENERIC,	    ' ' },
+-    { "nobless",    LT_GENERIC,	    ' ' },
+-    { "nonvram",    LT_GENERIC,	    ' ' },
+-    { "brokenosx",  LT_GENERIC,	    ' ' },
+-    { "usemount",   LT_GENERIC,	    ' ' },
+-    { "mntpoint",   LT_GENERIC,	    '=' },
+-    { "partition",  LT_GENERIC,	    '=' },
+-    { "device",	    LT_GENERIC,	    '=' },
+-    { "fstype",	    LT_GENERIC,	    '=' },
+-    { "initrd",	    LT_INITRD,	    '=',	';' },
+-    { "append",	    LT_KERNELARGS,  '=' },
+-    { "boot",	    LT_BOOT,	    '=' },
+-    { "lba",	    LT_LBA,	    ' ' },
+-    { NULL,	    0, 0 },
++	{"label", LT_TITLE, '='},
++	{"root", LT_ROOT, '='},
++	{"default", LT_DEFAULT, '='},
++	{"image", LT_KERNEL, '='},
++	{"bsd", LT_GENERIC, '='},
++	{"macos", LT_GENERIC, '='},
++	{"macosx", LT_GENERIC, '='},
++	{"magicboot", LT_GENERIC, '='},
++	{"darwin", LT_GENERIC, '='},
++	{"timeout", LT_GENERIC, '='},
++	{"install", LT_GENERIC, '='},
++	{"fstype", LT_GENERIC, '='},
++	{"hfstype", LT_GENERIC, '='},
++	{"delay", LT_GENERIC, '='},
++	{"defaultos", LT_GENERIC, '='},
++	{"init-message", LT_GENERIC, '='},
++	{"enablecdboot", LT_GENERIC, ' '},
++	{"enableofboot", LT_GENERIC, ' '},
++	{"enablenetboot", LT_GENERIC, ' '},
++	{"nonvram", LT_GENERIC, ' '},
++	{"hide", LT_GENERIC, ' '},
++	{"protect", LT_GENERIC, ' '},
++	{"nobless", LT_GENERIC, ' '},
++	{"nonvram", LT_GENERIC, ' '},
++	{"brokenosx", LT_GENERIC, ' '},
++	{"usemount", LT_GENERIC, ' '},
++	{"mntpoint", LT_GENERIC, '='},
++	{"partition", LT_GENERIC, '='},
++	{"device", LT_GENERIC, '='},
++	{"fstype", LT_GENERIC, '='},
++	{"initrd", LT_INITRD, '=', ';'},
++	{"append", LT_KERNELARGS, '='},
++	{"boot", LT_BOOT, '='},
++	{"lba", LT_LBA, ' '},
++	{NULL, 0, 0},
+ };
+ 
+ struct keywordTypes liloKeywords[] = {
+-    { "label",	    LT_TITLE,	    '=' },
+-    { "root",	    LT_ROOT,	    '=' },
+-    { "default",    LT_DEFAULT,	    '=' },
+-    { "image",	    LT_KERNEL,	    '=' },
+-    { "other",	    LT_OTHER,	    '=' },
+-    { "initrd",	    LT_INITRD,	    '=' },
+-    { "append",	    LT_KERNELARGS,  '=' },
+-    { "boot",	    LT_BOOT,	    '=' },
+-    { "lba",	    LT_LBA,	    ' ' },
+-    { NULL,	    0, 0 },
++	{"label", LT_TITLE, '='},
++	{"root", LT_ROOT, '='},
++	{"default", LT_DEFAULT, '='},
++	{"image", LT_KERNEL, '='},
++	{"other", LT_OTHER, '='},
++	{"initrd", LT_INITRD, '='},
++	{"append", LT_KERNELARGS, '='},
++	{"boot", LT_BOOT, '='},
++	{"lba", LT_LBA, ' '},
++	{NULL, 0, 0},
+ };
+ 
+ struct keywordTypes eliloKeywords[] = {
+-    { "label",	    LT_TITLE,	    '=' },
+-    { "root",	    LT_ROOT,	    '=' },
+-    { "default",    LT_DEFAULT,	    '=' },
+-    { "image",	    LT_KERNEL,	    '=' },
+-    { "initrd",	    LT_INITRD,	    '=' },
+-    { "append",	    LT_KERNELARGS,  '=' },
+-    { "vmm",	    LT_HYPER,       '=' },
+-    { NULL,	    0, 0 },
++	{"label", LT_TITLE, '='},
++	{"root", LT_ROOT, '='},
++	{"default", LT_DEFAULT, '='},
++	{"image", LT_KERNEL, '='},
++	{"initrd", LT_INITRD, '='},
++	{"append", LT_KERNELARGS, '='},
++	{"vmm", LT_HYPER, '='},
++	{NULL, 0, 0},
+ };
+ 
+ struct keywordTypes siloKeywords[] = {
+-    { "label",	    LT_TITLE,	    '=' },
+-    { "root",	    LT_ROOT,	    '=' },
+-    { "default",    LT_DEFAULT,	    '=' },
+-    { "image",	    LT_KERNEL,	    '=' },
+-    { "other",	    LT_OTHER,	    '=' },
+-    { "initrd",	    LT_INITRD,	    '=' },
+-    { "append",	    LT_KERNELARGS,  '=' },
+-    { "boot",	    LT_BOOT,	    '=' },
+-    { NULL,	    0, 0 },
++	{"label", LT_TITLE, '='},
++	{"root", LT_ROOT, '='},
++	{"default", LT_DEFAULT, '='},
++	{"image", LT_KERNEL, '='},
++	{"other", LT_OTHER, '='},
++	{"initrd", LT_INITRD, '='},
++	{"append", LT_KERNELARGS, '='},
++	{"boot", LT_BOOT, '='},
++	{NULL, 0, 0},
+ };
+ 
+ struct keywordTypes ziplKeywords[] = {
+-    { "target",     LT_BOOTROOT,    '=' },
+-    { "image",      LT_KERNEL,      '=' },
+-    { "ramdisk",    LT_INITRD,      '=' },
+-    { "parameters", LT_KERNELARGS,  '=' },
+-    { "default",    LT_DEFAULT,     '=' },
+-    { NULL,         0, 0 },
++	{"target", LT_BOOTROOT, '='},
++	{"image", LT_KERNEL, '='},
++	{"ramdisk", LT_INITRD, '='},
++	{"parameters", LT_KERNELARGS, '='},
++	{"default", LT_DEFAULT, '='},
++	{NULL, 0, 0},
+ };
+ 
+ struct keywordTypes extlinuxKeywords[] = {
+-    { "label",	    LT_TITLE,	    ' ' },
+-    { "root",	    LT_ROOT,	    ' ' },
+-    { "default",    LT_DEFAULT,	    ' ' },
+-    { "kernel",	    LT_KERNEL,	    ' ' },
+-    { "initrd",	    LT_INITRD,      ' ',	',' },
+-    { "append",	    LT_KERNELARGS,  ' ' },
+-    { "prompt",     LT_UNKNOWN,     ' ' },
+-    { "fdt",        LT_DEVTREE,     ' ' },
+-    { "fdtdir",     LT_DEVTREE,     ' ' },
+-    { NULL,	    0, 0 },
++	{"label", LT_TITLE, ' '},
++	{"root", LT_ROOT, ' '},
++	{"default", LT_DEFAULT, ' '},
++	{"kernel", LT_KERNEL, ' '},
++	{"initrd", LT_INITRD, ' ', ','},
++	{"append", LT_KERNELARGS, ' '},
++	{"prompt", LT_UNKNOWN, ' '},
++	{"fdt", LT_DEVTREE, ' '},
++	{"fdtdir", LT_DEVTREE, ' '},
++	{NULL, 0, 0},
+ };
++
+ int useextlinuxmenu;
+ struct configFileInfo eliloConfigType = {
+-    .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
+-    .keywords = eliloKeywords,
+-    .entryStart = LT_KERNEL,
+-    .needsBootPrefix = 1,
+-    .argsInQuotes = 1,
+-    .mbConcatArgs = 1,
+-    .titlePosition = 1,
++	.defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
++	.keywords = eliloKeywords,
++	.entryStart = LT_KERNEL,
++	.needsBootPrefix = 1,
++	.argsInQuotes = 1,
++	.mbConcatArgs = 1,
++	.titlePosition = 1,
+ };
+ 
+ struct configFileInfo liloConfigType = {
+-    .defaultConfig = "/etc/lilo.conf",
+-    .keywords = liloKeywords,
+-    .entryStart = LT_KERNEL,
+-    .argsInQuotes = 1,
+-    .maxTitleLength = 15,
+-    .titlePosition = 1,
++	.defaultConfig = "/etc/lilo.conf",
++	.keywords = liloKeywords,
++	.entryStart = LT_KERNEL,
++	.argsInQuotes = 1,
++	.maxTitleLength = 15,
++	.titlePosition = 1,
+ };
+ 
+ struct configFileInfo yabootConfigType = {
+-    .defaultConfig = "/etc/yaboot.conf",
+-    .keywords = yabootKeywords,
+-    .entryStart = LT_KERNEL,
+-    .needsBootPrefix = 1,
+-    .argsInQuotes = 1,
+-    .maxTitleLength = 15,
+-    .mbAllowExtraInitRds = 1,
+-    .titlePosition = 1,
++	.defaultConfig = "/etc/yaboot.conf",
++	.keywords = yabootKeywords,
++	.entryStart = LT_KERNEL,
++	.needsBootPrefix = 1,
++	.argsInQuotes = 1,
++	.maxTitleLength = 15,
++	.mbAllowExtraInitRds = 1,
++	.titlePosition = 1,
+ };
+ 
+ struct configFileInfo siloConfigType = {
+-    .defaultConfig = "/etc/silo.conf",
+-    .keywords = siloKeywords,
+-    .entryStart = LT_KERNEL,
+-    .needsBootPrefix = 1,
+-    .argsInQuotes = 1,
+-    .maxTitleLength = 15,
+-    .titlePosition = 1,
++	.defaultConfig = "/etc/silo.conf",
++	.keywords = siloKeywords,
++	.entryStart = LT_KERNEL,
++	.needsBootPrefix = 1,
++	.argsInQuotes = 1,
++	.maxTitleLength = 15,
++	.titlePosition = 1,
+ };
+ 
+ struct configFileInfo ziplConfigType = {
+-    .defaultConfig = "/etc/zipl.conf",
+-    .keywords = ziplKeywords,
+-    .entryStart = LT_TITLE,
+-    .argsInQuotes = 1,
+-    .titleBracketed = 1,
++	.defaultConfig = "/etc/zipl.conf",
++	.keywords = ziplKeywords,
++	.entryStart = LT_TITLE,
++	.argsInQuotes = 1,
++	.titleBracketed = 1,
+ };
+ 
+ struct configFileInfo extlinuxConfigType = {
+-    .defaultConfig = "/boot/extlinux/extlinux.conf",
+-    .keywords = extlinuxKeywords,
+-    .caseInsensitive = 1,
+-    .entryStart = LT_TITLE,
+-    .needsBootPrefix = 1,
+-    .maxTitleLength = 255,
+-    .mbAllowExtraInitRds = 1,
+-    .defaultIsUnquoted = 1,
+-    .titlePosition = 1,
++	.defaultConfig = "/boot/extlinux/extlinux.conf",
++	.keywords = extlinuxKeywords,
++	.caseInsensitive = 1,
++	.entryStart = LT_TITLE,
++	.needsBootPrefix = 1,
++	.maxTitleLength = 255,
++	.mbAllowExtraInitRds = 1,
++	.defaultIsUnquoted = 1,
++	.titlePosition = 1,
+ };
+ 
+ struct grubConfig {
+-    struct singleLine * theLines;
+-    struct singleEntry * entries;
+-    char * primaryIndent;
+-    char * secondaryIndent;
+-    int defaultImage;		    /* -1 if none specified -- this value is
+-				     * written out, overriding original */
+-    int fallbackImage;		    /* just like defaultImage */
+-    int flags;
+-    struct configFileInfo * cfi;
++	struct singleLine *theLines;
++	struct singleEntry *entries;
++	char *primaryIndent;
++	char *secondaryIndent;
++	int defaultImage;	/* -1 if none specified -- this value is
++				 * written out, overriding original */
++	int fallbackImage;	/* just like defaultImage */
++	int flags;
++	struct configFileInfo *cfi;
+ };
+ 
+ blkid_cache blkid;
+ 
+-struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
+-struct singleEntry * findEntryByPath(struct grubConfig * cfg, 
+-				     const char * path, const char * prefix,
+-				     int * index);
+-struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
+-				      int * index);
+-static int readFile(int fd, char ** bufPtr);
+-static void lineInit(struct singleLine * line);
+-struct singleLine * lineDup(struct singleLine * line);
+-static void lineFree(struct singleLine * line);
+-static int lineWrite(FILE * out, struct singleLine * line,
+-		     struct configFileInfo * cfi);
+-static int getNextLine(char ** bufPtr, struct singleLine * line,
+-		       struct configFileInfo * cfi);
+-static char * getRootSpecifier(char * str);
+-static void requote(struct singleLine *line, struct configFileInfo * cfi);
+-static void insertElement(struct singleLine * line,
+-			  const char * item, int insertHere,
+-			  struct configFileInfo * cfi);
+-static void removeElement(struct singleLine * line, int removeHere);
+-static struct keywordTypes * getKeywordByType(enum lineType_e type,
+-					      struct configFileInfo * cfi);
+-static enum lineType_e getTypeByKeyword(char * keyword, 
+-					struct configFileInfo * cfi);
+-static struct singleLine * getLineByType(enum lineType_e type,
+-					 struct singleLine * line);
+-static int checkForExtLinux(struct grubConfig * config);
+-struct singleLine * addLineTmpl(struct singleEntry * entry,
+-                                struct singleLine * tmplLine,
+-                                struct singleLine * prevLine,
+-                                const char * val,
+-				struct configFileInfo * cfi);
+-struct singleLine *  addLine(struct singleEntry * entry,
+-                             struct configFileInfo * cfi,
+-                             enum lineType_e type, char * defaultIndent,
+-                             const char * val);
++struct singleEntry *findEntryByIndex(struct grubConfig *cfg, int index);
++struct singleEntry *findEntryByPath(struct grubConfig *cfg,
++				    const char *path, const char *prefix,
++				    int *index);
++struct singleEntry *findEntryByTitle(struct grubConfig *cfg, char *title,
++				     int *index);
++static int readFile(int fd, char **bufPtr);
++static void lineInit(struct singleLine *line);
++struct singleLine *lineDup(struct singleLine *line);
++static void lineFree(struct singleLine *line);
++static int lineWrite(FILE * out, struct singleLine *line,
++		     struct configFileInfo *cfi);
++static int getNextLine(char **bufPtr, struct singleLine *line,
++		       struct configFileInfo *cfi);
++static char *getRootSpecifier(char *str);
++static void requote(struct singleLine *line, struct configFileInfo *cfi);
++static void insertElement(struct singleLine *line,
++			  const char *item, int insertHere,
++			  struct configFileInfo *cfi);
++static void removeElement(struct singleLine *line, int removeHere);
++static struct keywordTypes *getKeywordByType(enum lineType_e type,
++					     struct configFileInfo *cfi);
++static enum lineType_e getTypeByKeyword(char *keyword,
++					struct configFileInfo *cfi);
++static struct singleLine *getLineByType(enum lineType_e type,
++					struct singleLine *line);
++static int checkForExtLinux(struct grubConfig *config);
++struct singleLine *addLineTmpl(struct singleEntry *entry,
++			       struct singleLine *tmplLine,
++			       struct singleLine *prevLine,
++			       const char *val, struct configFileInfo *cfi);
++struct singleLine *addLine(struct singleEntry *entry,
++			   struct configFileInfo *cfi,
++			   enum lineType_e type, char *defaultIndent,
++			   const char *val);
+ 
+-static char * sdupprintf(const char *format, ...)
++static char *sdupprintf(const char *format, ...)
+ #ifdef __GNUC__
+-        __attribute__ ((format (printf, 1, 2)));
++    __attribute__ ((format(printf, 1, 2)));
+ #else
+-        ;
++;
+ #endif
+ 
+-static char * sdupprintf(const char *format, ...) {
+-    char *buf = NULL;
+-    char c;
+-    va_list args;
+-    size_t size = 0;
+-    va_start(args, format);
+-    
+-    /* XXX requires C99 vsnprintf behavior */
+-    size = vsnprintf(&c, 1, format, args) + 1;
+-    if (size == -1) {
+-	printf("ERROR: vsnprintf behavior is not C99\n");
+-	abort();
+-    }
++static char *sdupprintf(const char *format, ...)
++{
++	char *buf = NULL;
++	char c;
++	va_list args;
++	size_t size = 0;
++	va_start(args, format);
+ 
+-    va_end(args);
+-    va_start(args, format);
++	/* XXX requires C99 vsnprintf behavior */
++	size = vsnprintf(&c, 1, format, args) + 1;
++	if (size == -1) {
++		printf("ERROR: vsnprintf behavior is not C99\n");
++		abort();
++	}
+ 
+-    buf = malloc(size);
+-    if (buf == NULL)
+-	return NULL;
+-    vsnprintf(buf, size, format, args);
+-    va_end (args);
++	va_end(args);
++	va_start(args, format);
+ 
+-    return buf;
++	buf = malloc(size);
++	if (buf == NULL)
++		return NULL;
++	vsnprintf(buf, size, format, args);
++	va_end(args);
++
++	return buf;
+ }
+ 
+ static enum lineType_e preferredLineType(enum lineType_e type,
+-					 struct configFileInfo *cfi) {
+-    if (isEfi && cfi == &grub2ConfigType) {
+-	switch (type) {
+-	case LT_KERNEL:
+-	    return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
+-	case LT_INITRD:
+-	    return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
+-	default:
+-	    return type;
+-	}
++					 struct configFileInfo *cfi)
++{
++	if (isEfi && cfi == &grub2ConfigType) {
++		switch (type) {
++		case LT_KERNEL:
++			return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
++		case LT_INITRD:
++			return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
++		default:
++			return type;
++		}
+ #if defined(__i386__) || defined(__x86_64__)
+-    } else if (cfi == &grub2ConfigType) {
+-	switch (type) {
+-	case LT_KERNEL:
+-	    return LT_KERNEL_16;
+-	case LT_INITRD:
+-	    return LT_INITRD_16;
+-	default:
+-	    return type;
+-	}
++	} else if (cfi == &grub2ConfigType) {
++		switch (type) {
++		case LT_KERNEL:
++			return LT_KERNEL_16;
++		case LT_INITRD:
++			return LT_INITRD_16;
++		default:
++			return type;
++		}
+ #endif
+-    }
+-    return type;
++	}
++	return type;
+ }
+ 
+-static struct keywordTypes * getKeywordByType(enum lineType_e type,
+-					      struct configFileInfo * cfi) {
+-    for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
+-	if (kw->type == type)
+-	    return kw;
+-    }
+-    return NULL;
++static struct keywordTypes *getKeywordByType(enum lineType_e type,
++					     struct configFileInfo *cfi)
++{
++	for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) {
++		if (kw->type == type)
++			return kw;
++	}
++	return NULL;
+ }
+ 
+-static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
+-    struct keywordTypes *kt = getKeywordByType(type, cfi);
+-    if (kt)
+-	return kt->key;
+-    return "unknown";
++static char *getKeyByType(enum lineType_e type, struct configFileInfo *cfi)
++{
++	struct keywordTypes *kt = getKeywordByType(type, cfi);
++	if (kt)
++		return kt->key;
++	return "unknown";
+ }
+ 
+-static char * getpathbyspec(char *device) {
+-    if (!blkid)
+-        blkid_get_cache(&blkid, NULL);
++static char *getpathbyspec(char *device)
++{
++	if (!blkid)
++		blkid_get_cache(&blkid, NULL);
+ 
+-    return blkid_get_devname(blkid, device, NULL);
++	return blkid_get_devname(blkid, device, NULL);
+ }
+ 
+-static char * getuuidbydev(char *device) {
+-    if (!blkid)
+-	blkid_get_cache(&blkid, NULL);
++static char *getuuidbydev(char *device)
++{
++	if (!blkid)
++		blkid_get_cache(&blkid, NULL);
+ 
+-    return blkid_get_tag_value(blkid, "UUID", device);
++	return blkid_get_tag_value(blkid, "UUID", device);
+ }
+ 
+-static enum lineType_e getTypeByKeyword(char * keyword, 
+-					struct configFileInfo * cfi) {
+-    for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
+-	if (cfi->caseInsensitive) {
+-	    if (!strcasecmp(keyword, kw->key))
+-                return kw->type;
+-	} else {
+-	    if (!strcmp(keyword, kw->key))
+-	        return kw->type;
++static enum lineType_e getTypeByKeyword(char *keyword,
++					struct configFileInfo *cfi)
++{
++	for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) {
++		if (cfi->caseInsensitive) {
++			if (!strcasecmp(keyword, kw->key))
++				return kw->type;
++		} else {
++			if (!strcmp(keyword, kw->key))
++				return kw->type;
++		}
+ 	}
+-    }
+-    return LT_UNKNOWN;
++	return LT_UNKNOWN;
+ }
+ 
+-static struct singleLine * getLineByType(enum lineType_e type,
+-					 struct singleLine * line) {
+-    dbgPrintf("getLineByType(%d): ", type);
+-    for (; line; line = line->next) {
+-	dbgPrintf("%d:%s ", line->type, 
+-		  line->numElements ? line->elements[0].item : "(empty)");
+-	if (line->type & type) break;
+-    }
+-    dbgPrintf(line ? "\n" : " (failed)\n");
+-    return line;
++static struct singleLine *getLineByType(enum lineType_e type,
++					struct singleLine *line)
++{
++	dbgPrintf("getLineByType(%d): ", type);
++	for (; line; line = line->next) {
++		dbgPrintf("%d:%s ", line->type,
++			  line->numElements ? line->elements[0].
++			  item : "(empty)");
++		if (line->type & type)
++			break;
++	}
++	dbgPrintf(line ? "\n" : " (failed)\n");
++	return line;
+ }
+ 
+-static int isBracketedTitle(struct singleLine * line) {
+-    if (line->numElements == 1 && *line->elements[0].item == '[') {
+-        int len = strlen(line->elements[0].item);
+-        if (*(line->elements[0].item + len - 1) == ']') {
+-            /* FIXME: this is a hack... */
+-            if (strcmp(line->elements[0].item, "[defaultboot]")) {
+-                return 1;
+-            }
+-        }
+-    }
+-    return 0;
++static int isBracketedTitle(struct singleLine *line)
++{
++	if (line->numElements == 1 && *line->elements[0].item == '[') {
++		int len = strlen(line->elements[0].item);
++		if (*(line->elements[0].item + len - 1) == ']') {
++			/* FIXME: this is a hack... */
++			if (strcmp(line->elements[0].item, "[defaultboot]")) {
++				return 1;
++			}
++		}
++	}
++	return 0;
+ }
+ 
+-static int isEntryStart(struct singleLine * line,
+-                            struct configFileInfo * cfi) {
+-    return line->type == cfi->entryStart || line->type == LT_OTHER ||
+-	(cfi->titleBracketed && isBracketedTitle(line));
++static int isEntryStart(struct singleLine *line, struct configFileInfo *cfi)
++{
++	return line->type == cfi->entryStart || line->type == LT_OTHER ||
++	    (cfi->titleBracketed && isBracketedTitle(line));
+ }
+ 
+ /* extract the title from within brackets (for zipl) */
+-static char * extractTitle(struct grubConfig *cfg, struct singleLine * line) {
+-    /* bracketed title... let's extract it */
+-    char * title = NULL;
+-    if (line->type == LT_TITLE) {
+-	char *tmp = line->elements[cfg->cfi->titlePosition].item;
+-	if (cfg->cfi->titleBracketed) {
+-	    tmp++;
+-	    title = strdup(tmp);
+-	    *(title + strlen(title) - 1) = '\0';
+-	} else {
+-	    title = strdup(tmp);
+-	}
+-    } else if (line->type == LT_MENUENTRY)
+-	title = strdup(line->elements[1].item);
+-    else
+-	return NULL;
+-    return title;
+-}
+-
+-static int readFile(int fd, char ** bufPtr) {
+-    int alloced = 0, size = 0, i = 0;
+-    char * buf = NULL;
+-
+-    do {
+-	size += i;
+-	if ((size + 1024) > alloced) {
+-	    alloced += 4096;
+-	    buf = realloc(buf, alloced + 1);
+-	}
+-    } while ((i = read(fd, buf + size, 1024)) > 0);
+-
+-    if (i < 0) {
+-	fprintf(stderr, _("error reading input: %s\n"), strerror(errno));
+-        free(buf);
+-	return 1;
+-    }
+-
+-    buf = realloc(buf, size + 2);
+-    if (size == 0)
+-        buf[size++] = '\n';
+-    else 
+-        if (buf[size - 1] != '\n')
+-            buf[size++] = '\n';
+-    buf[size] = '\0';
+-
+-    *bufPtr = buf;
+-
+-    return 0;
+-}
+-
+-static void lineInit(struct singleLine * line) {
+-    line->indent = NULL;
+-    line->elements = NULL;
+-    line->numElements = 0;
+-    line->next = NULL;
+-}
+-
+-struct singleLine * lineDup(struct singleLine * line) {
+-    struct singleLine * newLine = malloc(sizeof(*newLine));
+-
+-    newLine->indent = strdup(line->indent);
+-    newLine->next = NULL;
+-    newLine->type = line->type;
+-    newLine->numElements = line->numElements;
+-    newLine->elements = malloc(sizeof(*newLine->elements) * 
+-			       newLine->numElements);
+-
+-    for (int i = 0; i < newLine->numElements; i++) {
+-	newLine->elements[i].indent = strdup(line->elements[i].indent);
+-	newLine->elements[i].item = strdup(line->elements[i].item);
+-    }
+-
+-    return newLine;
+-}
+-
+-static void lineFree(struct singleLine * line) {
+-    if (line->indent) free(line->indent);
+-
+-    for (int i = 0; i < line->numElements; i++) {
+-	free(line->elements[i].item); 
+-	free(line->elements[i].indent); 
+-    }
+-
+-    if (line->elements) free(line->elements);
+-    lineInit(line);
++static char *extractTitle(struct grubConfig *cfg, struct singleLine *line)
++{
++	/* bracketed title... let's extract it */
++	char *title = NULL;
++	if (line->type == LT_TITLE) {
++		char *tmp = line->elements[cfg->cfi->titlePosition].item;
++		if (cfg->cfi->titleBracketed) {
++			tmp++;
++			title = strdup(tmp);
++			*(title + strlen(title) - 1) = '\0';
++		} else {
++			title = strdup(tmp);
++		}
++	} else if (line->type == LT_MENUENTRY)
++		title = strdup(line->elements[1].item);
++	else
++		return NULL;
++	return title;
+ }
+ 
+-static int lineWrite(FILE * out, struct singleLine * line,
+-		     struct configFileInfo * cfi) {
+-    if (fprintf(out, "%s", line->indent) == -1) return -1;
++static int readFile(int fd, char **bufPtr)
++{
++	int alloced = 0, size = 0, i = 0;
++	char *buf = NULL;
+ 
+-    for (int i = 0; i < line->numElements; i++) {
+-	/* Need to handle this, because we strip the quotes from
+-	 * menuentry when read it. */
+-	if (line->type == LT_MENUENTRY && i == 1) {
+-	    if(!isquote(*line->elements[i].item)) {
+-		int substring = 0;
+-		/* If the line contains nested quotes, we did not strip
+-		 * the "interna" quotes and we must use the right quotes
+-		 * again when writing the updated file. */
+-		for (int j = i; j < line->numElements; j++) {
+-		    if (strchr(line->elements[i].item, '\'') != NULL) {
+-		       substring = 1;
+-		       fprintf(out, "\"%s\"", line->elements[i].item);
+-		       break;
+-		    }
++	do {
++		size += i;
++		if ((size + 1024) > alloced) {
++			alloced += 4096;
++			buf = realloc(buf, alloced + 1);
+ 		}
+-		if (!substring)
+-		    fprintf(out, "\'%s\'", line->elements[i].item);
+-	    } else {
+-		fprintf(out, "%s", line->elements[i].item);
+-	    }
+-	    fprintf(out, "%s", line->elements[i].indent);
++	} while ((i = read(fd, buf + size, 1024)) > 0);
+ 
+-	    continue;
++	if (i < 0) {
++		fprintf(stderr, _("error reading input: %s\n"),
++			strerror(errno));
++		free(buf);
++		return 1;
+ 	}
+ 
+-	if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
+-	    if (fputc('"', out) == EOF) return -1;
+-
+-	if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
+-	if (i < line->numElements - 1)
+-	    if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
+-    }
++	buf = realloc(buf, size + 2);
++	if (size == 0)
++		buf[size++] = '\n';
++	else if (buf[size - 1] != '\n')
++		buf[size++] = '\n';
++	buf[size] = '\0';
+ 
+-    if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
+-	if (fputc('"', out) == EOF) return -1;
++	*bufPtr = buf;
+ 
+-    if (fprintf(out, "\n") == -1) return -1;
+-
+-    return 0;
++	return 0;
+ }
+ 
+-/* we've guaranteed that the buffer ends w/ \n\0 */
+-static int getNextLine(char ** bufPtr, struct singleLine * line,
+-                       struct configFileInfo * cfi) {
+-    char * end;
+-    char * start = *bufPtr;
+-    char * chptr;
+-    int elementsAlloced = 0;
+-    struct lineElement * element;
+-    int first = 1;
+-
+-    lineFree(line);
+-
+-    end = strchr(start, '\n');
+-    *end = '\0';
+-    *bufPtr = end + 1;
+-
+-    for (chptr = start; *chptr && isspace(*chptr); chptr++) ;
+-
+-    line->indent = strndup(start, chptr - start);
+-    start = chptr;
+-
+-    while (start < end) {
+-	/* we know !isspace(*start) */
++static void lineInit(struct singleLine *line)
++{
++	line->indent = NULL;
++	line->elements = NULL;
++	line->numElements = 0;
++	line->next = NULL;
++}
+ 
+-	if (elementsAlloced == line->numElements) {
+-	    elementsAlloced += 5;
+-	    line->elements = realloc(line->elements,
+-				sizeof(*line->elements) * elementsAlloced);
+-	}
++struct singleLine *lineDup(struct singleLine *line)
++{
++	struct singleLine *newLine = malloc(sizeof(*newLine));
+ 
+-	element = line->elements + line->numElements;
++	newLine->indent = strdup(line->indent);
++	newLine->next = NULL;
++	newLine->type = line->type;
++	newLine->numElements = line->numElements;
++	newLine->elements = malloc(sizeof(*newLine->elements) *
++				   newLine->numElements);
+ 
+-	chptr = start;
+-	while (*chptr && !isspace(*chptr)) {
+-	    if (first && *chptr == '=') break; 
+-	    chptr++;
++	for (int i = 0; i < newLine->numElements; i++) {
++		newLine->elements[i].indent = strdup(line->elements[i].indent);
++		newLine->elements[i].item = strdup(line->elements[i].item);
+ 	}
+-	element->item = strndup(start, chptr - start);
+-	start = chptr;
+-
+-        /* lilo actually accepts the pathological case of append = " foo " */
+-        if (*start == '=')
+-            chptr = start + 1;
+-        else 
+-            chptr = start;
+-
+-        do {
+-            for (; *chptr && isspace(*chptr); chptr++);
+-            if (*chptr == '=')
+-                chptr = chptr + 1;
+-        } while (isspace(*chptr));
+-
+-	element->indent = strndup(start, chptr - start);
+-	start = chptr;
+ 
+-	line->numElements++;
+-	first = 0;
+-    }
+-
+-    if (!line->numElements)
+-	line->type = LT_WHITESPACE;
+-    else {
+-	line->type = getTypeByKeyword(line->elements[0].item, cfi);
+-	if (line->type == LT_UNKNOWN) {
+-            /* zipl does [title] instead of something reasonable like all
+-             * the other boot loaders.  kind of ugly */
+-            if (cfi->titleBracketed && isBracketedTitle(line)) {
+-                line->type = LT_TITLE;
+-            }
+-
+-	    /* this is awkward, but we need to be able to handle keywords
+-	       that begin with a # (specifically for #boot in grub.conf),
+-	       but still make comments lines with no elements (everything
+-	       stored in the indent */
+-	    if (*line->elements[0].item == '#') {
+-		char * fullLine;
+-		int len;
+-
+-		len = strlen(line->indent);
+-		for (int i = 0; i < line->numElements; i++)
+-		    len += strlen(line->elements[i].item) + 
+-			   strlen(line->elements[i].indent);
++	return newLine;
++}
+ 
+-		fullLine = malloc(len + 1);
+-		strcpy(fullLine, line->indent);
++static void lineFree(struct singleLine *line)
++{
++	if (line->indent)
+ 		free(line->indent);
+-		line->indent = fullLine;
+ 
+-		for (int i = 0; i < line->numElements; i++) {
+-		    strcat(fullLine, line->elements[i].item);
+-		    strcat(fullLine, line->elements[i].indent);
+-		    free(line->elements[i].item);
+-		    free(line->elements[i].indent);
++	for (int i = 0; i < line->numElements; i++) {
++		free(line->elements[i].item);
++		free(line->elements[i].indent);
++	}
++
++	if (line->elements)
++		free(line->elements);
++	lineInit(line);
++}
++
++static int lineWrite(FILE * out, struct singleLine *line,
++		     struct configFileInfo *cfi)
++{
++	if (fprintf(out, "%s", line->indent) == -1)
++		return -1;
++
++	for (int i = 0; i < line->numElements; i++) {
++		/* Need to handle this, because we strip the quotes from
++		 * menuentry when read it. */
++		if (line->type == LT_MENUENTRY && i == 1) {
++			if (!isquote(*line->elements[i].item)) {
++				int substring = 0;
++				/* If the line contains nested quotes, we did
++				 * not strip the "interna" quotes and we must
++				 * use the right quotes again when writing
++				 * the updated file. */
++				for (int j = i; j < line->numElements; j++) {
++					if (strchr(line->elements[i].item, '\'')
++					    != NULL) {
++						substring = 1;
++						fprintf(out, "\"%s\"",
++							line->elements[i].item);
++						break;
++					}
++				}
++				if (!substring)
++					fprintf(out, "\'%s\'",
++						line->elements[i].item);
++			} else {
++				fprintf(out, "%s", line->elements[i].item);
++			}
++			fprintf(out, "%s", line->elements[i].indent);
++
++			continue;
++		}
++
++		if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
++			if (fputc('"', out) == EOF)
++				return -1;
++
++		if (fprintf(out, "%s", line->elements[i].item) == -1)
++			return -1;
++		if (i < line->numElements - 1)
++			if (fprintf(out, "%s", line->elements[i].indent) == -1)
++				return -1;
++	}
++
++	if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
++		if (fputc('"', out) == EOF)
++			return -1;
++
++	if (fprintf(out, "\n") == -1)
++		return -1;
++
++	return 0;
++}
++
++/* we've guaranteed that the buffer ends w/ \n\0 */
++static int getNextLine(char **bufPtr, struct singleLine *line,
++		       struct configFileInfo *cfi)
++{
++	char *end;
++	char *start = *bufPtr;
++	char *chptr;
++	int elementsAlloced = 0;
++	struct lineElement *element;
++	int first = 1;
++
++	lineFree(line);
++
++	end = strchr(start, '\n');
++	*end = '\0';
++	*bufPtr = end + 1;
++
++	for (chptr = start; *chptr && isspace(*chptr); chptr++) ;
++
++	line->indent = strndup(start, chptr - start);
++	start = chptr;
++
++	while (start < end) {
++		/* we know !isspace(*start) */
++
++		if (elementsAlloced == line->numElements) {
++			elementsAlloced += 5;
++			line->elements = realloc(line->elements,
++						 sizeof(*line->elements) *
++						 elementsAlloced);
++		}
++
++		element = line->elements + line->numElements;
++
++		chptr = start;
++		while (*chptr && !isspace(*chptr)) {
++			if (first && *chptr == '=')
++				break;
++			chptr++;
+ 		}
++		element->item = strndup(start, chptr - start);
++		start = chptr;
++
++		/* lilo actually accepts the pathological case of
++		 * append = " foo " */
++		if (*start == '=')
++			chptr = start + 1;
++		else
++			chptr = start;
++
++		do {
++			for (; *chptr && isspace(*chptr); chptr++) ;
++			if (*chptr == '=')
++				chptr = chptr + 1;
++		} while (isspace(*chptr));
++
++		element->indent = strndup(start, chptr - start);
++		start = chptr;
++
++		line->numElements++;
++		first = 0;
++	}
+ 
++	if (!line->numElements)
+ 		line->type = LT_WHITESPACE;
+-		line->numElements = 0;
+-	    }
+-	} else {
+-		struct keywordTypes *kw;
+-
+-		kw = getKeywordByType(line->type, cfi);
+-
+-		/* space isn't the only separator, we need to split
+-		 * elements up more
+-		 */
+-		if (!isspace(kw->separatorChar)) {
+-		    char indent[2] = "";
+-		    indent[0] = kw->separatorChar;
+-		    for (int i = 1; i < line->numElements; i++) {
+-			char *p;
+-			int numNewElements;
+-
+-			numNewElements = 0;
+-			p = line->elements[i].item;
+-			while (*p != '\0') {
+-				if (*p == kw->separatorChar)
+-					numNewElements++;
+-				p++;
+-			}
+-			if (line->numElements + numNewElements >= elementsAlloced) {
+-				elementsAlloced += numNewElements + 5;
+-				line->elements = realloc(line->elements,
+-					    sizeof(*line->elements) * elementsAlloced);
++	else {
++		line->type = getTypeByKeyword(line->elements[0].item, cfi);
++		if (line->type == LT_UNKNOWN) {
++			/* zipl does [title] instead of something reasonable
++			 * like all the other boot loaders.  kind of ugly */
++			if (cfi->titleBracketed && isBracketedTitle(line)) {
++				line->type = LT_TITLE;
+ 			}
+ 
+-			for (int j = line->numElements; j > i; j--) {
+-				line->elements[j + numNewElements] = line->elements[j];
+-			}
+-			line->numElements += numNewElements;
++			/* this is awkward, but we need to be able to handle
++			 * keywords that begin with a # (specifically for
++			 * #boot in grub.conf), but still make comments lines
++			 * with no elements (everything stored in the indent
++			 */
++			if (*line->elements[0].item == '#') {
++				char *fullLine;
++				int len;
++
++				len = strlen(line->indent);
++				for (int i = 0; i < line->numElements; i++)
++					len += strlen(line->elements[i].item) +
++					    strlen(line->elements[i].indent);
+ 
+-			p = line->elements[i].item;
+-			while (*p != '\0') {
++				fullLine = malloc(len + 1);
++				strcpy(fullLine, line->indent);
++				free(line->indent);
++				line->indent = fullLine;
+ 
+-				while (*p != kw->separatorChar && *p != '\0') p++;
+-				if (*p == '\0') {
+-					break;
++				for (int i = 0; i < line->numElements; i++) {
++					strcat(fullLine,
++					       line->elements[i].item);
++					strcat(fullLine,
++					       line->elements[i].indent);
++					free(line->elements[i].item);
++					free(line->elements[i].indent);
+ 				}
+ 
+-				line->elements[i + 1].indent = line->elements[i].indent;
+-				line->elements[i].indent = strdup(indent);
+-				*p++ = '\0';
+-				i++;
+-				line->elements[i].item = strdup(p);
++				line->type = LT_WHITESPACE;
++				line->numElements = 0;
++			}
++		} else {
++			struct keywordTypes *kw;
++
++			kw = getKeywordByType(line->type, cfi);
++
++			/* space isn't the only separator, we need to split
++			 * elements up more
++			 */
++			if (!isspace(kw->separatorChar)) {
++				char indent[2] = "";
++				indent[0] = kw->separatorChar;
++				for (int i = 1; i < line->numElements; i++) {
++					char *p;
++					int numNewElements;
++
++					numNewElements = 0;
++					p = line->elements[i].item;
++					while (*p != '\0') {
++						if (*p == kw->separatorChar)
++							numNewElements++;
++						p++;
++					}
++					if (line->numElements +
++					    numNewElements >= elementsAlloced) {
++						elementsAlloced +=
++						    numNewElements + 5;
++						line->elements =
++						    realloc(line->elements,
++							    sizeof(*line->
++								   elements) *
++							    elementsAlloced);
++					}
++
++					for (int j = line->numElements; j > i;
++					     j--) {
++						line->elements[j +
++							       numNewElements] =
++						    line->elements[j];
++					}
++					line->numElements += numNewElements;
++
++					p = line->elements[i].item;
++					while (*p != '\0') {
++
++						while (*p != kw->separatorChar
++						       && *p != '\0')
++							p++;
++						if (*p == '\0') {
++							break;
++						}
++
++						line->elements[i + 1].indent =
++						    line->elements[i].indent;
++						line->elements[i].indent =
++						    strdup(indent);
++						*p++ = '\0';
++						i++;
++						line->elements[i].item =
++						    strdup(p);
++					}
++				}
+ 			}
+-		    }
+ 		}
+ 	}
+-    }
+ 
+-    return 0;
++	return 0;
+ }
+ 
+ static int isnumber(const char *s)
+ {
+-    int i;
+-    for (i = 0; s[i] != '\0'; i++)
+-	if (s[i] < '0' || s[i] > '9')
+-	    return 0;
+-    return i;
++	int i;
++	for (i = 0; s[i] != '\0'; i++)
++		if (s[i] < '0' || s[i] > '9')
++			return 0;
++	return i;
+ }
+ 
+-static struct grubConfig * readConfig(const char * inName,
+-				      struct configFileInfo * cfi) {
+-    int in;
+-    char * incoming = NULL, * head;
+-    int rc;
+-    int sawEntry = 0;
+-    int movedLine = 0;
+-    struct grubConfig * cfg;
+-    struct singleLine * last = NULL, * line, * defaultLine = NULL;
+-    char * end;
+-    struct singleEntry * entry = NULL;
+-    int len;
+-    char * buf;
+-
+-    if (inName == NULL) {
+-        printf("Could not find bootloader configuration\n");
+-        exit(1);
+-    } else if (!strcmp(inName, "-")) {
+-	in = 0;
+-    } else {
+-	if ((in = open(inName, O_RDONLY)) < 0) {
+-	    fprintf(stderr, _("error opening %s for read: %s\n"),
+-		    inName, strerror(errno));
+-	    return NULL;
+-	}
+-    }
+-
+-    rc = readFile(in, &incoming);
+-    close(in);
+-    if (rc) return NULL;
+-
+-    head = incoming;
+-    cfg = malloc(sizeof(*cfg));
+-    cfg->primaryIndent = strdup("");
+-    cfg->secondaryIndent = strdup("\t");
+-    cfg->flags = GRUB_CONFIG_NO_DEFAULT;
+-    cfg->cfi = cfi;
+-    cfg->theLines = NULL;
+-    cfg->entries = NULL;
+-    cfg->fallbackImage = 0;
+-
+-    /* copy everything we have */
+-    while (*head) {
+-	line = malloc(sizeof(*line));
+-	lineInit(line);
+-
+-	if (getNextLine(&head, line, cfi)) {
+-	    free(line);
+-	    /* XXX memory leak of everything in cfg */
+-	    return NULL;
+-	}
+-
+-	if (!sawEntry && line->numElements) {
+-	    free(cfg->primaryIndent);
+-	    cfg->primaryIndent = strdup(line->indent);
+-	} else if (line->numElements) {
+-	    free(cfg->secondaryIndent);
+-	    cfg->secondaryIndent = strdup(line->indent);
+-	}
+-
+-	if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
+-	    sawEntry = 1;
+-	    if (!entry) {
+-		cfg->entries = malloc(sizeof(*entry));
+-		entry = cfg->entries;
+-	    } else {
+-		entry->next = malloc(sizeof(*entry));
+-		entry = entry->next;
+-	    }
+-
+-	    entry->skip = 0;
+-            entry->multiboot = 0;
+-	    entry->lines = NULL;
+-	    entry->next = NULL;
++static struct grubConfig *readConfig(const char *inName,
++				     struct configFileInfo *cfi)
++{
++	int in;
++	char *incoming = NULL, *head;
++	int rc;
++	int sawEntry = 0;
++	int movedLine = 0;
++	struct grubConfig *cfg;
++	struct singleLine *last = NULL, *line, *defaultLine = NULL;
++	char *end;
++	struct singleEntry *entry = NULL;
++	int len;
++	char *buf;
++
++	if (inName == NULL) {
++		printf("Could not find bootloader configuration\n");
++		exit(1);
++	} else if (!strcmp(inName, "-")) {
++		in = 0;
++	} else {
++		if ((in = open(inName, O_RDONLY)) < 0) {
++			fprintf(stderr, _("error opening %s for read: %s\n"),
++				inName, strerror(errno));
++			return NULL;
++		}
+ 	}
+ 
+-	if (line->type == LT_SET_VARIABLE) {
+-	    dbgPrintf("found 'set' command (%d elements): ", line->numElements);
+-	    dbgPrintf("%s", line->indent);
+-	    for (int i = 0; i < line->numElements; i++)
+-		dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
+-	    dbgPrintf("\n");
+-	    struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
+-	    if (kwType && line->numElements == 3 &&
+-		    !strcmp(line->elements[1].item, kwType->key) &&
+-		    !is_special_grub2_variable(line->elements[2].item)) {
+-		dbgPrintf("Line sets default config\n");
+-		cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
+-		defaultLine = line;
+-	    }
+-
+-        } else if (iskernel(line->type)) {
+-	    /* if by some freak chance this is multiboot and the "module"
+-	     * lines came earlier in the template, make sure to use LT_HYPER 
+-	     * instead of LT_KERNEL now
+-	     */
+-	    if (entry && entry->multiboot)
+-		line->type = LT_HYPER;
+-
+-        } else if (line->type == LT_MBMODULE) {
+-	    /* go back and fix the LT_KERNEL line to indicate LT_HYPER
+-	     * instead, now that we know this is a multiboot entry.
+-	     * This only applies to grub, but that's the only place we
+-	     * should find LT_MBMODULE lines anyway.
+-	     */
+-	    for (struct singleLine *l = entry->lines; l; l = l->next) {
+-		if (l->type == LT_HYPER)
+-		    break;
+-		else if (iskernel(l->type)) {
+-		    l->type = LT_HYPER;
+-		    break;
+-		}
+-	    }
+-            entry->multiboot = 1;
+-
+-	} else if (line->type == LT_HYPER) {
+-	    entry->multiboot = 1;
+-
+-	} else if (line->type == LT_FALLBACK && line->numElements == 2) {
+-	    cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
+-	    if (*end) cfg->fallbackImage = -1;
+-
+-	} else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
+-                (line->type == LT_TITLE && line->numElements > 1)) {
+-	    /* make the title/default a single argument (undoing our parsing) */
+-	    len = 0;
+-	    for (int i = 1; i < line->numElements; i++) {
+-		len += strlen(line->elements[i].item);
+-		len += strlen(line->elements[i].indent);
+-	    }
+-	    buf = malloc(len + 1);
+-	    *buf = '\0';
+-
+-	    for (int i = 1; i < line->numElements; i++) {
+-		strcat(buf, line->elements[i].item);
+-		free(line->elements[i].item);
+-
+-		if ((i + 1) != line->numElements) {
+-		    strcat(buf, line->elements[i].indent);
+-		    free(line->elements[i].indent);
+-		}
+-	    }
+-
+-	    line->elements[1].indent = 
+-		    line->elements[line->numElements - 1].indent;
+-	    line->elements[1].item = buf;
+-	    line->numElements = 2;
+-	} else if (line->type == LT_MENUENTRY && line->numElements > 3) {
+-	    /* let --remove-kernel="TITLE=what" work */
+-	    len = 0;
+-	    char *extras;
+-	    char *title;
+-	    /* initially unseen value */
+-	    char quote_char = '\0';
+-
+-	    for (int i = 1; i < line->numElements; i++) {
+-		len += strlen(line->elements[i].item);
+-		len += strlen(line->elements[i].indent);
+-	    }
+-	    buf = malloc(len + 1);
+-	    *buf = '\0';
+-
+-	    /* allocate mem for extra flags. */
+-	    extras = malloc(len + 1);
+-	    *extras = '\0';
+-
+-	    /* get title. */
+-	    for (int i = 0; i < line->numElements; i++) {
+-		if (!strcmp(line->elements[i].item, "menuentry"))
+-		    continue;
+-		if (isquote(*line->elements[i].item) && quote_char == '\0') {
+-		    /* ensure we properly pair off quotes */
+-		    quote_char = *line->elements[i].item;
+-		    title = line->elements[i].item + 1;
+-		} else {
+-		    title = line->elements[i].item;
++	rc = readFile(in, &incoming);
++	close(in);
++	if (rc)
++		return NULL;
++
++	head = incoming;
++	cfg = malloc(sizeof(*cfg));
++	cfg->primaryIndent = strdup("");
++	cfg->secondaryIndent = strdup("\t");
++	cfg->flags = GRUB_CONFIG_NO_DEFAULT;
++	cfg->cfi = cfi;
++	cfg->theLines = NULL;
++	cfg->entries = NULL;
++	cfg->fallbackImage = 0;
++
++	/* copy everything we have */
++	while (*head) {
++		line = malloc(sizeof(*line));
++		lineInit(line);
++
++		if (getNextLine(&head, line, cfi)) {
++			free(line);
++			/* XXX memory leak of everything in cfg */
++			return NULL;
+ 		}
+ 
+-		len = strlen(title);
+-	        if (title[len-1] == quote_char) {
+-		    strncat(buf, title,len-1);
+-		    break;
+-		} else {
+-		    strcat(buf, title);
+-		    strcat(buf, line->elements[i].indent);
++		if (!sawEntry && line->numElements) {
++			free(cfg->primaryIndent);
++			cfg->primaryIndent = strdup(line->indent);
++		} else if (line->numElements) {
++			free(cfg->secondaryIndent);
++			cfg->secondaryIndent = strdup(line->indent);
+ 		}
+-	    }
+-
+-	    /* get extras */
+-	    int count = 0;
+-	    quote_char = '\0';
+-	    for (int i = 0; i < line->numElements; i++) {
+-		if (count >= 2) {
+-		    strcat(extras, line->elements[i].item);
+-		    strcat(extras, line->elements[i].indent);
+-		}
+-
+-		if (!strcmp(line->elements[i].item, "menuentry"))
+-		    continue;
+ 
+-		/* count ' or ", there should be two in menuentry line. */
+-		if (isquote(*line->elements[i].item) && quote_char == '\0') {
+-		    /* ensure we properly pair off quotes */
+-	            quote_char = *line->elements[i].item;
+-		    count++;
++		if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
++			sawEntry = 1;
++			if (!entry) {
++				cfg->entries = malloc(sizeof(*entry));
++				entry = cfg->entries;
++			} else {
++				entry->next = malloc(sizeof(*entry));
++				entry = entry->next;
++			}
++
++			entry->skip = 0;
++			entry->multiboot = 0;
++			entry->lines = NULL;
++			entry->next = NULL;
+ 		}
+ 
+-		len = strlen(line->elements[i].item);
+-
+-		if (line->elements[i].item[len -1] == quote_char)
+-		    count++;
+-
+-		/* ok, we get the final ' or ", others are extras. */
+-            }
+-	    line->elements[1].indent =
+-		line->elements[line->numElements - 2].indent;
+-	    line->elements[1].item = buf;
+-	    line->elements[2].indent =
+-		line->elements[line->numElements - 2].indent;
+-	    line->elements[2].item = extras;
+-	    line->numElements = 3;
+-	} else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
+-	    /* Strip off any " which may be present; they'll be put back
+-	       on write. This is one of the few (the only?) places that grubby
+-	       canonicalizes the output */
+-
+-	    if (line->numElements >= 2) {
+-		int last, len;
+-
+-		if (isquote(*line->elements[1].item))
+-		    memmove(line->elements[1].item, line->elements[1].item + 1,
+-			    strlen(line->elements[1].item + 1) + 1);
+-
+-		last = line->numElements - 1;
+-		len = strlen(line->elements[last].item) - 1;
+-		if (isquote(line->elements[last].item[len]))
+-		    line->elements[last].item[len] = '\0';
+-	    }
+-	}
++		if (line->type == LT_SET_VARIABLE) {
++			dbgPrintf("found 'set' command (%d elements): ",
++				  line->numElements);
++			dbgPrintf("%s", line->indent);
++			for (int i = 0; i < line->numElements; i++)
++				dbgPrintf("\"%s\"%s", line->elements[i].item,
++					  line->elements[i].indent);
++			dbgPrintf("\n");
++			struct keywordTypes *kwType =
++			    getKeywordByType(LT_DEFAULT, cfi);
++			if (kwType && line->numElements == 3
++			    && !strcmp(line->elements[1].item, kwType->key)
++			    && !is_special_grub2_variable(line->elements[2].
++							  item)) {
++				dbgPrintf("Line sets default config\n");
++				cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
++				defaultLine = line;
++			}
++
++		} else if (iskernel(line->type)) {
++			/* if by some freak chance this is multiboot and the
++			 * "module" lines came earlier in the template, make
++			 * sure to use LT_HYPER instead of LT_KERNEL now
++			 */
++			if (entry && entry->multiboot)
++				line->type = LT_HYPER;
++
++		} else if (line->type == LT_MBMODULE) {
++			/* go back and fix the LT_KERNEL line to indicate
++			 * LT_HYPER instead, now that we know this is a
++			 * multiboot entry.  This only applies to grub, but
++			 * that's the only place we should find LT_MBMODULE
++			 * lines anyway.
++			 */
++			for (struct singleLine * l = entry->lines; l;
++			     l = l->next) {
++				if (l->type == LT_HYPER)
++					break;
++				else if (iskernel(l->type)) {
++					l->type = LT_HYPER;
++					break;
++				}
++			}
++			entry->multiboot = 1;
++
++		} else if (line->type == LT_HYPER) {
++			entry->multiboot = 1;
++
++		} else if (line->type == LT_FALLBACK && line->numElements == 2) {
++			cfg->fallbackImage =
++			    strtol(line->elements[1].item, &end, 10);
++			if (*end)
++				cfg->fallbackImage = -1;
++
++		} else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted)
++			   || (line->type == LT_TITLE
++			       && line->numElements > 1)) {
++			/* make the title/default a single argument (undoing
++			 * our parsing) */
++			len = 0;
++			for (int i = 1; i < line->numElements; i++) {
++				len += strlen(line->elements[i].item);
++				len += strlen(line->elements[i].indent);
++			}
++			buf = malloc(len + 1);
++			*buf = '\0';
++
++			for (int i = 1; i < line->numElements; i++) {
++				strcat(buf, line->elements[i].item);
++				free(line->elements[i].item);
++
++				if ((i + 1) != line->numElements) {
++					strcat(buf, line->elements[i].indent);
++					free(line->elements[i].indent);
++				}
++			}
++
++			line->elements[1].indent =
++			    line->elements[line->numElements - 1].indent;
++			line->elements[1].item = buf;
++			line->numElements = 2;
++		} else if (line->type == LT_MENUENTRY && line->numElements > 3) {
++			/* let --remove-kernel="TITLE=what" work */
++			len = 0;
++			char *extras;
++			char *title;
++			/* initially unseen value */
++			char quote_char = '\0';
++
++			for (int i = 1; i < line->numElements; i++) {
++				len += strlen(line->elements[i].item);
++				len += strlen(line->elements[i].indent);
++			}
++			buf = malloc(len + 1);
++			*buf = '\0';
++
++			/* allocate mem for extra flags. */
++			extras = malloc(len + 1);
++			*extras = '\0';
++
++			/* get title. */
++			for (int i = 0; i < line->numElements; i++) {
++				if (!strcmp
++				    (line->elements[i].item, "menuentry"))
++					continue;
++				if (isquote(*line->elements[i].item)
++				    && quote_char == '\0') {
++					/* ensure we properly pair off quotes */
++					quote_char = *line->elements[i].item;
++					title = line->elements[i].item + 1;
++				} else {
++					title = line->elements[i].item;
++				}
++
++				len = strlen(title);
++				if (title[len - 1] == quote_char) {
++					strncat(buf, title, len - 1);
++					break;
++				} else {
++					strcat(buf, title);
++					strcat(buf, line->elements[i].indent);
++				}
++			}
++
++			/* get extras */
++			int count = 0;
++			quote_char = '\0';
++			for (int i = 0; i < line->numElements; i++) {
++				if (count >= 2) {
++					strcat(extras, line->elements[i].item);
++					strcat(extras,
++					       line->elements[i].indent);
++				}
++
++				if (!strcmp
++				    (line->elements[i].item, "menuentry"))
++					continue;
++
++				/* count ' or ", there should be two in menuentry line. */
++				if (isquote(*line->elements[i].item)
++				    && quote_char == '\0') {
++					/* ensure we properly pair off quotes */
++					quote_char = *line->elements[i].item;
++					count++;
++				}
++
++				len = strlen(line->elements[i].item);
++
++				if (line->elements[i].item[len - 1] ==
++				    quote_char)
++					count++;
++
++				/* ok, we get the final ' or ", others are extras. */
++			}
++			line->elements[1].indent =
++			    line->elements[line->numElements - 2].indent;
++			line->elements[1].item = buf;
++			line->elements[2].indent =
++			    line->elements[line->numElements - 2].indent;
++			line->elements[2].item = extras;
++			line->numElements = 3;
++		} else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
++			/* Strip off any " which may be present; they'll be
++			 * put back on write. This is one of the few (the
++			 * only?) places that grubby canonicalizes the output
++			 */
++			if (line->numElements >= 2) {
++				int last, len;
++
++				if (isquote(*line->elements[1].item))
++					memmove(line->elements[1].item,
++						line->elements[1].item + 1,
++						strlen(line->elements[1].item +
++						       1) + 1);
++
++				last = line->numElements - 1;
++				len = strlen(line->elements[last].item) - 1;
++				if (isquote(line->elements[last].item[len]))
++					line->elements[last].item[len] = '\0';
++			}
++		}
+ 
+-	if (line->type == LT_DEFAULT && line->numElements == 2) {
+-	    cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
+-	    defaultLine = line;
+-	}
++		if (line->type == LT_DEFAULT && line->numElements == 2) {
++			cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
++			defaultLine = line;
++		}
+ 
+-	/* If we find a generic config option which should live at the
+-	   top of the file, move it there. Old versions of grubby were
+-	   probably responsible for putting new images in the wrong 
+-	   place in front of it anyway. */
+-	if (sawEntry && line->type == LT_GENERIC) {
+-		struct singleLine **l = &cfg->theLines;
+-		struct singleLine **last_nonws = &cfg->theLines;
+-		while (*l) {
+-			if ((*l)->type != LT_WHITESPACE)
+-				last_nonws = &((*l)->next);
+-			l = &((*l)->next);
++		/* If we find a generic config option which should live at the
++		   top of the file, move it there. Old versions of grubby were
++		   probably responsible for putting new images in the wrong 
++		   place in front of it anyway. */
++		if (sawEntry && line->type == LT_GENERIC) {
++			struct singleLine **l = &cfg->theLines;
++			struct singleLine **last_nonws = &cfg->theLines;
++			while (*l) {
++				if ((*l)->type != LT_WHITESPACE)
++					last_nonws = &((*l)->next);
++				l = &((*l)->next);
++			}
++			line->next = *last_nonws;
++			*last_nonws = line;
++			movedLine = 1;
++			continue;	/* without setting 'last' */
+ 		}
+-		line->next = *last_nonws;
+-		*last_nonws = line;
+-		movedLine = 1;
+-		continue; /* without setting 'last' */
+-	}
+ 
+-	/* If a second line of whitespace happens after a generic option
+-	   which was moved, drop it. */
+-	if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {
+-		lineFree(line);
+-		free(line);
++		/* If a second line of whitespace happens after a generic
++		 * option which was moved, drop it. */
++		if (movedLine && line->type == LT_WHITESPACE
++		    && last->type == LT_WHITESPACE) {
++			lineFree(line);
++			free(line);
++			movedLine = 0;
++			continue;
++		}
+ 		movedLine = 0;
+-		continue;
+-	}
+-	movedLine = 0;
+ 
+-	if (sawEntry) {
+-	    if (!entry->lines)
+-		entry->lines = line;
+-	    else
+-		last->next = line;
+-	    dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
++		if (sawEntry) {
++			if (!entry->lines)
++				entry->lines = line;
++			else
++				last->next = line;
++			dbgPrintf("readConfig added %s to %p\n",
++				  getKeyByType(line->type, cfi), entry);
++
++			/* we could have seen this outside of an entry... if
++			 * so, we ignore it like any other line we don't grok
++			 */
++			if (line->type == LT_ENTRY_END && sawEntry)
++				sawEntry = 0;
++		} else {
++			if (!cfg->theLines)
++				cfg->theLines = line;
++			else
++				last->next = line;
++			dbgPrintf("readConfig added %s to cfg\n",
++				  getKeyByType(line->type, cfi));
++		}
+ 
+-	    /* we could have seen this outside of an entry... if so, we
+-	     * ignore it like any other line we don't grok */
+-	    if (line->type == LT_ENTRY_END && sawEntry)
+-		sawEntry = 0;
+-	} else {
+-	    if (!cfg->theLines)
+-		cfg->theLines = line;
+-	    else
+-		last->next = line;
+-	    dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
++		last = line;
+ 	}
+ 
+-	last = line;
+-    }
++	free(incoming);
++
++	dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
++	if (defaultLine) {
++		if (defaultLine->numElements > 2 &&
++		    cfi->defaultSupportSaved &&
++		    !strncmp(defaultLine->elements[2].item,
++			     "\"${saved_entry}\"", 16)) {
++			cfg->cfi->defaultIsSaved = 1;
++			cfg->defaultImage = DEFAULT_SAVED_GRUB2;
++			if (cfg->cfi->getEnv) {
++				char *defTitle =
++				    cfi->getEnv(cfg->cfi, "saved_entry");
++				if (defTitle) {
++					int index = 0;
++					if (isnumber(defTitle)) {
++						index = atoi(defTitle);
++						entry =
++						    findEntryByIndex(cfg,
++								     index);
++					} else {
++						entry =
++						    findEntryByTitle(cfg,
++								     defTitle,
++								     &index);
++					}
++					if (entry)
++						cfg->defaultImage = index;
++				}
++			}
++		} else if (cfi->defaultIsVariable) {
++			char *value = defaultLine->elements[2].item;
++			while (*value && (*value == '"' || *value == '\'' ||
++					  *value == ' ' || *value == '\t'))
++				value++;
++			cfg->defaultImage = strtol(value, &end, 10);
++			while (*end && (*end == '"' || *end == '\'' ||
++					*end == ' ' || *end == '\t'))
++				end++;
++			if (*end)
++				cfg->defaultImage = -1;
++		} else if (cfi->defaultSupportSaved &&
++			   !strncmp(defaultLine->elements[1].item, "saved",
++				    5)) {
++			cfg->defaultImage = DEFAULT_SAVED;
++		} else if (cfi->defaultIsIndex) {
++			cfg->defaultImage =
++			    strtol(defaultLine->elements[1].item, &end, 10);
++			if (*end)
++				cfg->defaultImage = -1;
++		} else if (defaultLine->numElements >= 2) {
++			int i = 0;
++			while ((entry = findEntryByIndex(cfg, i))) {
++				for (line = entry->lines; line;
++				     line = line->next)
++					if (line->type == LT_TITLE)
++						break;
+ 
+-    free(incoming);
++				if (!cfi->titleBracketed) {
++					if (line && (line->numElements >= 2) &&
++					    !strcmp(defaultLine->elements[1].
++						    item,
++						    line->elements[1].item))
++						break;
++				} else if (line) {
++					if (!strcmp
++					    (defaultLine->elements[1].item,
++					     extractTitle(cfg, line)))
++						break;
++				}
++				i++;
++				entry = NULL;
++			}
+ 
+-    dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
+-    if (defaultLine) {
+-        if (defaultLine->numElements > 2 &&
+-	    cfi->defaultSupportSaved &&
+-	    !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
+-		cfg->cfi->defaultIsSaved = 1;
+-		cfg->defaultImage = DEFAULT_SAVED_GRUB2;
+-		if (cfg->cfi->getEnv) {
+-		    char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
+-		    if (defTitle) {
++			if (entry) {
++				cfg->defaultImage = i;
++			} else {
++				cfg->defaultImage = -1;
++			}
++		}
++	} else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
++		char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
++		if (defTitle) {
+ 			int index = 0;
+ 			if (isnumber(defTitle)) {
+-			    index = atoi(defTitle);
+-			    entry = findEntryByIndex(cfg, index);
++				index = atoi(defTitle);
++				entry = findEntryByIndex(cfg, index);
+ 			} else {
+-			    entry = findEntryByTitle(cfg, defTitle, &index);
++				entry = findEntryByTitle(cfg, defTitle, &index);
+ 			}
+ 			if (entry)
+-			    cfg->defaultImage = index;
+-		    }
++				cfg->defaultImage = index;
+ 		}
+-	} else if (cfi->defaultIsVariable) {
+-	    char *value = defaultLine->elements[2].item;
+-	    while (*value && (*value == '"' || *value == '\'' ||
+-		    *value == ' ' || *value == '\t'))
+-		value++;
+-	    cfg->defaultImage = strtol(value, &end, 10);
+-	    while (*end && (*end == '"' || *end == '\'' ||
+-		    *end == ' ' || *end == '\t'))
+-		end++;
+-	    if (*end) cfg->defaultImage = -1;
+-	} else if (cfi->defaultSupportSaved && 
+-		!strncmp(defaultLine->elements[1].item, "saved", 5)) {
+-	    cfg->defaultImage = DEFAULT_SAVED;
+-	} else if (cfi->defaultIsIndex) {
+-	    cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
+-	    if (*end) cfg->defaultImage = -1;
+-	} else if (defaultLine->numElements >= 2) {
+-	    int i = 0;
+-	    while ((entry = findEntryByIndex(cfg, i))) {
+-		for (line = entry->lines; line; line = line->next)
+-		    if (line->type == LT_TITLE) break;
+-
+-                if (!cfi->titleBracketed) {
+-                    if (line && (line->numElements >= 2) && 
+-                        !strcmp(defaultLine->elements[1].item,
+-                                line->elements[1].item)) break;
+-                } else if (line) {
+-                    if (!strcmp(defaultLine->elements[1].item, 
+-                                extractTitle(cfg, line))) break;
+-                }
+-		i++;
+-		entry = NULL;
+-	    }
+-
+-	    if (entry){
+-	        cfg->defaultImage = i;
+-	    }else{
+-	        cfg->defaultImage = -1;
+-	    }
+-	}
+-    } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
+-	char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
+-	if (defTitle) {
+-	    int index = 0;
+-	    if (isnumber(defTitle)) {
+-		index = atoi(defTitle);
+-		entry = findEntryByIndex(cfg, index);
+-	    } else {
+-		entry = findEntryByTitle(cfg, defTitle, &index);
+-	    }
+-	    if (entry)
+-		cfg->defaultImage = index;
+-	}
+-    } else {
+-        cfg->defaultImage = 0;
+-    }
+-
+-    return cfg;
+-}
+-
+-static void writeDefault(FILE * out, char * indent,
+-			 char * separator, struct grubConfig * cfg) {
+-    struct singleEntry * entry;
+-    struct singleLine * line;
+-    int i;
+-
+-    if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT)
+-	return;
+-
+-    if (cfg->defaultImage == DEFAULT_SAVED)
+-	fprintf(out, "%sdefault%ssaved\n", indent, separator);
+-    else if (cfg->cfi->defaultIsSaved) {
+-	fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
+-	if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
+-	    char *title;
+-	    entry = findEntryByIndex(cfg, cfg->defaultImage);
+-	    line = getLineByType(LT_MENUENTRY, entry->lines);
+-	    if (!line)
+-		line = getLineByType(LT_TITLE, entry->lines);
+-	    if (line) {
+-		title = extractTitle(cfg, line);
+-		if (title)
+-		    cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
+-	    }
+-	}
+-    } else if (cfg->defaultImage > -1) {
+-	if (cfg->cfi->defaultIsIndex) {
+-	    if (cfg->cfi->defaultIsVariable) {
+-	        fprintf(out, "%sset default=\"%d\"\n", indent,
+-			cfg->defaultImage);
+-	    } else {
+-		fprintf(out, "%sdefault%s%d\n", indent, separator,
+-			cfg->defaultImage);
+-	    }
+ 	} else {
+-	    int image = cfg->defaultImage;
++		cfg->defaultImage = 0;
++	}
+ 
+-	    entry = cfg->entries;
+-	    while (entry && entry->skip)
+-		entry = entry->next;
++	return cfg;
++}
+ 
+-	    i = 0;
+-	    while (entry && i < image) {
+-		entry = entry->next;
++static void writeDefault(FILE * out, char *indent,
++			 char *separator, struct grubConfig *cfg)
++{
++	struct singleEntry *entry;
++	struct singleLine *line;
++	int i;
+ 
+-		while (entry && entry->skip)
+-		    entry = entry->next;
+-		i++;
+-	    }
+-
+-	    if (!entry)
++	if (!cfg->defaultImage && cfg->flags == GRUB_CONFIG_NO_DEFAULT)
+ 		return;
+ 
+-	    line = getLineByType(LT_TITLE, entry->lines);
+-
+-	    if (line && line->numElements >= 2)
+-		fprintf(out, "%sdefault%s%s\n", indent, separator,
+-			line->elements[1].item);
+-            else if (line && (line->numElements == 1) &&
+-                     cfg->cfi->titleBracketed) {
+-		char *title = extractTitle(cfg, line);
+-		if (title) {
+-		    fprintf(out, "%sdefault%s%s\n", indent, separator, title);
+-		    free(title);
++	if (cfg->defaultImage == DEFAULT_SAVED)
++		fprintf(out, "%sdefault%ssaved\n", indent, separator);
++	else if (cfg->cfi->defaultIsSaved) {
++		fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
++		if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
++			char *title;
++			entry = findEntryByIndex(cfg, cfg->defaultImage);
++			line = getLineByType(LT_MENUENTRY, entry->lines);
++			if (!line)
++				line = getLineByType(LT_TITLE, entry->lines);
++			if (line) {
++				title = extractTitle(cfg, line);
++				if (title)
++					cfg->cfi->setEnv(cfg->cfi,
++							 "saved_entry", title);
++			}
++		}
++	} else if (cfg->defaultImage > -1) {
++		if (cfg->cfi->defaultIsIndex) {
++			if (cfg->cfi->defaultIsVariable) {
++				fprintf(out, "%sset default=\"%d\"\n", indent,
++					cfg->defaultImage);
++			} else {
++				fprintf(out, "%sdefault%s%d\n", indent,
++					separator, cfg->defaultImage);
++			}
++		} else {
++			int image = cfg->defaultImage;
++
++			entry = cfg->entries;
++			while (entry && entry->skip)
++				entry = entry->next;
++
++			i = 0;
++			while (entry && i < image) {
++				entry = entry->next;
++
++				while (entry && entry->skip)
++					entry = entry->next;
++				i++;
++			}
++
++			if (!entry)
++				return;
++
++			line = getLineByType(LT_TITLE, entry->lines);
++
++			if (line && line->numElements >= 2)
++				fprintf(out, "%sdefault%s%s\n", indent,
++					separator, line->elements[1].item);
++			else if (line && (line->numElements == 1)
++				 && cfg->cfi->titleBracketed) {
++				char *title = extractTitle(cfg, line);
++				if (title) {
++					fprintf(out, "%sdefault%s%s\n", indent,
++						separator, title);
++					free(title);
++				}
++			}
+ 		}
+-            }
+ 	}
+-    }
+ }
+ 
+-static int writeConfig(struct grubConfig * cfg, char * outName, 
+-		       const char * prefix) {
+-    FILE * out;
+-    struct singleLine * line;
+-    struct singleEntry * entry;
+-    char * tmpOutName;
+-    int needs = MAIN_DEFAULT;
+-    struct stat sb;
+-    int i;
+-
+-    if (!strcmp(outName, "-")) {
+-	out = stdout;
+-	tmpOutName = NULL;
+-    } else {
+-	if (!lstat(outName, &sb) && S_ISLNK(sb.st_mode)) {
+-	    char * buf;
+-	    int len = 256;
+-	    int rc;
+-
+-	    /* most likely the symlink is relative, so change our
+-	       directory to the dir of the symlink */
+-	    char *dir = strdupa(outName);
+-	    rc = chdir(dirname(dir));
+-	    do {
+-		buf = alloca(len + 1);
+-		rc = readlink(basename(outName), buf, len);
+-		if (rc == len) len += 256;
+-	    } while (rc == len);
+-	    
+-	    if (rc < 0) {
+-		fprintf(stderr, _("grubby: error readlink link %s: %s\n"), 
+-			outName, strerror(errno));
+-		return 1;
+-	    }
+-
+-	    outName = buf;
+-	    outName[rc] = '\0';
+-	}
+-
+-	tmpOutName = alloca(strlen(outName) + 2);
+-	sprintf(tmpOutName, "%s-", outName);
+-	out = fopen(tmpOutName, "w");
+-	if (!out) {
+-	    fprintf(stderr, _("grubby: error creating %s: %s\n"), tmpOutName, 
+-		    strerror(errno));
+-	    return 1;
+-	}
+-
+-	if (!stat(outName, &sb)) {
+-	    if (chmod(tmpOutName, sb.st_mode & ~(S_IFMT))) {
+-		fprintf(stderr, _("grubby: error setting perms on %s: %s\n"),
+-		        tmpOutName, strerror(errno));
+-		fclose(out);
+-		unlink(tmpOutName);
+-                return 1;
+-	    }
+-	} 
+-    }
+-
+-    line = cfg->theLines;
+-    struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
+-    while (line) {
+-        if (line->type == LT_SET_VARIABLE && defaultKw &&
+-		line->numElements == 3 &&
+-		!strcmp(line->elements[1].item, defaultKw->key) &&
+-		!is_special_grub2_variable(line->elements[2].item)) {
+-	    writeDefault(out, line->indent, line->elements[0].indent, cfg);
+-	    needs &= ~MAIN_DEFAULT;
+-	} else if (line->type == LT_DEFAULT) {
+-	    writeDefault(out, line->indent, line->elements[0].indent, cfg);
+-	    needs &= ~MAIN_DEFAULT;
+-	} else if (line->type == LT_FALLBACK) {
+-	    if (cfg->fallbackImage > -1)
+-		fprintf(out, "%s%s%s%d\n", line->indent, 
+-			line->elements[0].item, line->elements[0].indent,
+-			cfg->fallbackImage);
++static int writeConfig(struct grubConfig *cfg, char *outName,
++		       const char *prefix)
++{
++	FILE *out;
++	struct singleLine *line;
++	struct singleEntry *entry;
++	char *tmpOutName;
++	int needs = MAIN_DEFAULT;
++	struct stat sb;
++	int i;
++
++	if (!strcmp(outName, "-")) {
++		out = stdout;
++		tmpOutName = NULL;
+ 	} else {
+-	    if (lineWrite(out, line, cfg->cfi) == -1) {
+-                fprintf(stderr, _("grubby: error writing %s: %s\n"),
+-                        tmpOutName, strerror(errno));
+-                fclose(out);
+-                unlink(tmpOutName);
+-                return 1;
+-            }
++		if (!lstat(outName, &sb) && S_ISLNK(sb.st_mode)) {
++			char *buf;
++			int len = 256;
++			int rc;
++
++			/* most likely the symlink is relative, so change our
++			   directory to the dir of the symlink */
++			char *dir = strdupa(outName);
++			rc = chdir(dirname(dir));
++			do {
++				buf = alloca(len + 1);
++				rc = readlink(basename(outName), buf, len);
++				if (rc == len)
++					len += 256;
++			} while (rc == len);
++
++			if (rc < 0) {
++				fprintf(stderr,
++					_
++					("grubby: error readlink link %s: %s\n"),
++					outName, strerror(errno));
++				return 1;
++			}
++
++			outName = buf;
++			outName[rc] = '\0';
++		}
++
++		tmpOutName = alloca(strlen(outName) + 2);
++		sprintf(tmpOutName, "%s-", outName);
++		out = fopen(tmpOutName, "w");
++		if (!out) {
++			fprintf(stderr, _("grubby: error creating %s: %s\n"),
++				tmpOutName, strerror(errno));
++			return 1;
++		}
++
++		if (!stat(outName, &sb)) {
++			if (chmod(tmpOutName, sb.st_mode & ~(S_IFMT))) {
++				fprintf(stderr,
++					_
++					("grubby: error setting perms on %s: %s\n"),
++					tmpOutName, strerror(errno));
++				fclose(out);
++				unlink(tmpOutName);
++				return 1;
++			}
++		}
+ 	}
+ 
+-	line = line->next;
+-    }
+-
+-    if (needs & MAIN_DEFAULT) {
+-	writeDefault(out, cfg->primaryIndent, "=", cfg);
+-	needs &= ~MAIN_DEFAULT;
+-    }
+-
+-    i = 0;
+-    while ((entry = findEntryByIndex(cfg, i++))) {
+-	if (entry->skip) continue;
+-
+-	line = entry->lines;
++	line = cfg->theLines;
++	struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
+ 	while (line) {
+-	    if (lineWrite(out, line, cfg->cfi) == -1) {
+-                fprintf(stderr, _("grubby: error writing %s: %s\n"),
+-                        tmpOutName, strerror(errno));
+-                fclose(out);
+-                unlink(tmpOutName);
+-                return 1;
+-            }
+-	    line = line->next;
++		if (line->type == LT_SET_VARIABLE && defaultKw &&
++		    line->numElements == 3 &&
++		    !strcmp(line->elements[1].item, defaultKw->key) &&
++		    !is_special_grub2_variable(line->elements[2].item)) {
++			writeDefault(out, line->indent,
++				     line->elements[0].indent, cfg);
++			needs &= ~MAIN_DEFAULT;
++		} else if (line->type == LT_DEFAULT) {
++			writeDefault(out, line->indent,
++				     line->elements[0].indent, cfg);
++			needs &= ~MAIN_DEFAULT;
++		} else if (line->type == LT_FALLBACK) {
++			if (cfg->fallbackImage > -1)
++				fprintf(out, "%s%s%s%d\n", line->indent,
++					line->elements[0].item,
++					line->elements[0].indent,
++					cfg->fallbackImage);
++		} else {
++			if (lineWrite(out, line, cfg->cfi) == -1) {
++				fprintf(stderr,
++					_("grubby: error writing %s: %s\n"),
++					tmpOutName, strerror(errno));
++				fclose(out);
++				unlink(tmpOutName);
++				return 1;
++			}
++		}
++
++		line = line->next;
++	}
++
++	if (needs & MAIN_DEFAULT) {
++		writeDefault(out, cfg->primaryIndent, "=", cfg);
++		needs &= ~MAIN_DEFAULT;
++	}
++
++	i = 0;
++	while ((entry = findEntryByIndex(cfg, i++))) {
++		if (entry->skip)
++			continue;
++
++		line = entry->lines;
++		while (line) {
++			if (lineWrite(out, line, cfg->cfi) == -1) {
++				fprintf(stderr,
++					_("grubby: error writing %s: %s\n"),
++					tmpOutName, strerror(errno));
++				fclose(out);
++				unlink(tmpOutName);
++				return 1;
++			}
++			line = line->next;
++		}
+ 	}
+-    }
+ 
+-    if (tmpOutName) {
+-	if (rename(tmpOutName, outName)) {
+-	    fprintf(stderr, _("grubby: error moving %s to %s: %s\n"),
+-		    tmpOutName, outName, strerror(errno));
+-	    unlink(outName);
+-            return 1;
++	if (tmpOutName) {
++		if (rename(tmpOutName, outName)) {
++			fprintf(stderr,
++				_("grubby: error moving %s to %s: %s\n"),
++				tmpOutName, outName, strerror(errno));
++			unlink(outName);
++			return 1;
++		}
+ 	}
+-    }
+ 
+-    return 0;
++	return 0;
+ }
+ 
+-static int numEntries(struct grubConfig *cfg) {
+-    int i = 0;
+-    struct singleEntry * entry;
++static int numEntries(struct grubConfig *cfg)
++{
++	int i = 0;
++	struct singleEntry *entry;
+ 
+-    entry = cfg->entries;
+-    while (entry) {
+-        if (!entry->skip)
+-            i++;
+-        entry = entry->next;
+-    }
+-    return i;
++	entry = cfg->entries;
++	while (entry) {
++		if (!entry->skip)
++			i++;
++		entry = entry->next;
++	}
++	return i;
+ }
+ 
+ static char *findDiskForRoot()
+ {
+-    int fd;
+-    char buf[65536];
+-    char *devname;
+-    char *chptr;
+-    int rc;
+-
+-    if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
+-        fprintf(stderr, "grubby: failed to open %s: %s\n",
+-                _PATH_MOUNTED, strerror(errno));
+-        return NULL;
+-    }
+-
+-    rc = read(fd, buf, sizeof(buf) - 1);
+-    if (rc <= 0) {
+-        fprintf(stderr, "grubby: failed to read %s: %s\n",
+-                _PATH_MOUNTED, strerror(errno));
+-        close(fd);
+-        return NULL;
+-    }
+-    close(fd);
+-    buf[rc] = '\0';
+-    chptr = buf;
+-
+-    char *foundanswer = NULL;
+-
+-    while (chptr && chptr != buf+rc) {
+-        devname = chptr;
+-
+-        /*
+-         * The first column of a mtab entry is the device, but if the entry is a
+-         * special device it won't start with /, so move on to the next line.
+-         */
+-        if (*devname != '/') {
+-            chptr = strchr(chptr, '\n');
+-            if (chptr)
+-                chptr++;
+-            continue;
+-        }
+-
+-        /* Seek to the next space */
+-        chptr = strchr(chptr, ' ');
+-        if (!chptr) {
+-            fprintf(stderr, "grubby: error parsing %s: %s\n",
+-                    _PATH_MOUNTED, strerror(errno));
+-            return NULL;
+-        }
+-
+-        /*
+-         * The second column of a mtab entry is the mount point, we are looking
+-         * for '/' obviously.
+-         */
+-        if (*(++chptr) == '/' && *(++chptr) == ' ') {
+-            /* remember the last / entry in mtab */
+-           foundanswer = devname;
+-        }
+-
+-        /* Next line */
+-        chptr = strchr(chptr, '\n');
+-        if (chptr)
+-            chptr++;
+-    }
+-
+-    /* Return the last / entry found */
+-    if (foundanswer) {
+-        chptr = strchr(foundanswer, ' ');
+-        *chptr = '\0';
+-        return strdup(foundanswer);
+-    }
+-
+-    return NULL;
++	int fd;
++	char buf[65536];
++	char *devname;
++	char *chptr;
++	int rc;
++
++	if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
++		fprintf(stderr, "grubby: failed to open %s: %s\n",
++			_PATH_MOUNTED, strerror(errno));
++		return NULL;
++	}
++
++	rc = read(fd, buf, sizeof(buf) - 1);
++	if (rc <= 0) {
++		fprintf(stderr, "grubby: failed to read %s: %s\n",
++			_PATH_MOUNTED, strerror(errno));
++		close(fd);
++		return NULL;
++	}
++	close(fd);
++	buf[rc] = '\0';
++	chptr = buf;
++
++	char *foundanswer = NULL;
++
++	while (chptr && chptr != buf + rc) {
++		devname = chptr;
++
++		/*
++		 * The first column of a mtab entry is the device, but if the
++		 * entry is a special device it won't start with /, so move
++		 * on to the next line.
++		 */
++		if (*devname != '/') {
++			chptr = strchr(chptr, '\n');
++			if (chptr)
++				chptr++;
++			continue;
++		}
++
++		/* Seek to the next space */
++		chptr = strchr(chptr, ' ');
++		if (!chptr) {
++			fprintf(stderr, "grubby: error parsing %s: %s\n",
++				_PATH_MOUNTED, strerror(errno));
++			return NULL;
++		}
++
++		/*
++		 * The second column of a mtab entry is the mount point, we
++		 * are looking for '/' obviously.
++		 */
++		if (*(++chptr) == '/' && *(++chptr) == ' ') {
++			/* remember the last / entry in mtab */
++			foundanswer = devname;
++		}
++
++		/* Next line */
++		chptr = strchr(chptr, '\n');
++		if (chptr)
++			chptr++;
++	}
++
++	/* Return the last / entry found */
++	if (foundanswer) {
++		chptr = strchr(foundanswer, ' ');
++		*chptr = '\0';
++		return strdup(foundanswer);
++	}
++
++	return NULL;
+ }
+ 
+-void printEntry(struct singleEntry * entry, FILE *f) {
+-    int i;
+-    struct singleLine * line;
+-
+-    for (line = entry->lines; line; line = line->next) {
+-	log_message(f, "DBG: %s", line->indent);
+-	for (i = 0; i < line->numElements; i++) {
+-	    /* Need to handle this, because we strip the quotes from
+-	     * menuentry when read it. */
+-	    if (line->type == LT_MENUENTRY && i == 1) {
+-		if(!isquote(*line->elements[i].item))
+-		    log_message(f, "\'%s\'", line->elements[i].item);
+-		else
+-		    log_message(f, "%s", line->elements[i].item);
+-		log_message(f, "%s", line->elements[i].indent);
+-		
+-		continue;
+-	    }
+-	    
+-	    log_message(f, "%s%s",
+-		    line->elements[i].item, line->elements[i].indent);
++void printEntry(struct singleEntry *entry, FILE * f)
++{
++	int i;
++	struct singleLine *line;
++
++	for (line = entry->lines; line; line = line->next) {
++		log_message(f, "DBG: %s", line->indent);
++		for (i = 0; i < line->numElements; i++) {
++			/* Need to handle this, because we strip the quotes from
++			 * menuentry when read it. */
++			if (line->type == LT_MENUENTRY && i == 1) {
++				if (!isquote(*line->elements[i].item))
++					log_message(f, "\'%s\'",
++						    line->elements[i].item);
++				else
++					log_message(f, "%s",
++						    line->elements[i].item);
++				log_message(f, "%s", line->elements[i].indent);
++
++				continue;
++			}
++
++			log_message(f, "%s%s",
++				    line->elements[i].item,
++				    line->elements[i].indent);
++		}
++		log_message(f, "\n");
+ 	}
+-	log_message(f, "\n");
+-    }
+ }
+ 
+-void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
++void notSuitablePrintf(struct singleEntry *entry, int okay, const char *fmt,
++		       ...)
+ {
+-    static int once;
+-    va_list argp, argq;
+-
+-    va_start(argp, fmt);
+-
+-    va_copy(argq, argp);
+-    if (!once) {
+-	log_time(NULL);
+-	log_message(NULL, "command line: %s\n", saved_command_line);
+-    }
+-    log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
+-    log_vmessage(NULL, fmt, argq);
+-	
+-    printEntry(entry, NULL);
+-    va_end(argq);
+-
+-    if (!debug) {
++	static int once;
++	va_list argp, argq;
++
++	va_start(argp, fmt);
++
++	va_copy(argq, argp);
++	if (!once) {
++		log_time(NULL);
++		log_message(NULL, "command line: %s\n", saved_command_line);
++	}
++	log_message(NULL, "DBG: Image entry %s: ",
++		    okay ? "succeeded" : "failed");
++	log_vmessage(NULL, fmt, argq);
++
++	printEntry(entry, NULL);
++	va_end(argq);
++
++	if (!debug) {
++		once = 1;
++		va_end(argp);
++		return;
++	}
++
++	if (okay) {
++		va_end(argp);
++		return;
++	}
++
++	if (!once)
++		log_message(stderr, "DBG: command line: %s\n",
++			    saved_command_line);
+ 	once = 1;
+-    	va_end(argp);
+-	return;
+-    }
+-
+-    if (okay) {
++	fprintf(stderr, "DBG: Image entry failed: ");
++	vfprintf(stderr, fmt, argp);
++	printEntry(entry, stderr);
+ 	va_end(argp);
+-	return;
+-    }
+-
+-    if (!once)
+-	log_message(stderr, "DBG: command line: %s\n", saved_command_line);
+-    once = 1;
+-    fprintf(stderr, "DBG: Image entry failed: ");
+-    vfprintf(stderr, fmt, argp);
+-    printEntry(entry, stderr);
+-    va_end(argp);
+ }
+ 
+ #define beginswith(s, c) ((s) && (s)[0] == (c))
+@@ -1867,281 +1993,318 @@ static int endswith(const char *s, char c)
+ 	return s[slen] == c;
+ }
+ 
+-int suitableImage(struct singleEntry * entry, const char * bootPrefix,
+-		  int skipRemoved, int flags) {
+-    struct singleLine * line;
+-    char * fullName;
+-    int i;
+-    char * dev;
+-    char * rootspec;
+-    char * rootdev;
++int suitableImage(struct singleEntry *entry, const char *bootPrefix,
++		  int skipRemoved, int flags)
++{
++	struct singleLine *line;
++	char *fullName;
++	int i;
++	char *dev;
++	char *rootspec;
++	char *rootdev;
+ 
+-    if (skipRemoved && entry->skip) {
+-	notSuitablePrintf(entry, 0, "marked to skip\n");
+-	return 0;
+-    }
++	if (skipRemoved && entry->skip) {
++		notSuitablePrintf(entry, 0, "marked to skip\n");
++		return 0;
++	}
+ 
+-    line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
+-    if (!line) {
+-	notSuitablePrintf(entry, 0, "no line found\n");
+-	return 0;
+-    }
+-    if (line->numElements < 2) {
+-	notSuitablePrintf(entry, 0, "line has only %d elements\n",
+-	    line->numElements);
+-	return 0;
+-    }
+-
+-    if (flags & GRUBBY_BADIMAGE_OKAY) {
+-	    notSuitablePrintf(entry, 1, "\n");
+-	    return 1;
+-    }
+-
+-    fullName = alloca(strlen(bootPrefix) + 
+-		      strlen(line->elements[1].item) + 1);
+-    rootspec = getRootSpecifier(line->elements[1].item);
+-    int rootspec_offset = rootspec ? strlen(rootspec) : 0;
+-    int hasslash = endswith(bootPrefix, '/') ||
+-    	beginswith(line->elements[1].item + rootspec_offset, '/');
+-    sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
+-            line->elements[1].item + rootspec_offset);
+-    if (access(fullName, R_OK)) {
+-	notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
+-	return 0;
+-    }
+-    for (i = 2; i < line->numElements; i++) 
+-	if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
+-    if (i < line->numElements) {
+-	dev = line->elements[i].item + 5;
+-    } else {
+-	/* look for a lilo style LT_ROOT line */
+-	line = getLineByType(LT_ROOT, entry->lines);
+-
+-	if (line && line->numElements >= 2) {
+-	    dev = line->elements[1].item;
+-	} else {
+-	    /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
+-	     * grub+multiboot uses LT_MBMODULE for the args, so check that too.
+-	     */
+-	    line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
+-
+-            /* failed to find one */
+-            if (!line) {
++	line =
++	    getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | LT_KERNEL_16,
++			  entry->lines);
++	if (!line) {
+ 		notSuitablePrintf(entry, 0, "no line found\n");
+ 		return 0;
+-            }
++	}
++	if (line->numElements < 2) {
++		notSuitablePrintf(entry, 0, "line has only %d elements\n",
++				  line->numElements);
++		return 0;
++	}
++
++	if (flags & GRUBBY_BADIMAGE_OKAY) {
++		notSuitablePrintf(entry, 1, "\n");
++		return 1;
++	}
++
++	fullName = alloca(strlen(bootPrefix) +
++			  strlen(line->elements[1].item) + 1);
++	rootspec = getRootSpecifier(line->elements[1].item);
++	int rootspec_offset = rootspec ? strlen(rootspec) : 0;
++	int hasslash = endswith(bootPrefix, '/') ||
++	    beginswith(line->elements[1].item + rootspec_offset, '/');
++	sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
++		line->elements[1].item + rootspec_offset);
++	if (access(fullName, R_OK)) {
++		notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
++		return 0;
++	}
++	for (i = 2; i < line->numElements; i++)
++		if (!strncasecmp(line->elements[i].item, "root=", 5))
++			break;
++	if (i < line->numElements) {
++		dev = line->elements[i].item + 5;
++	} else {
++		/* look for a lilo style LT_ROOT line */
++		line = getLineByType(LT_ROOT, entry->lines);
++
++		if (line && line->numElements >= 2) {
++			dev = line->elements[1].item;
++		} else {
++			/* didn't succeed in finding a LT_ROOT, let's try
++			 * LT_KERNELARGS.  grub+multiboot uses LT_MBMODULE
++			 * for the args, so check that too.
++			 */
++			line =
++			    getLineByType(LT_KERNELARGS | LT_MBMODULE,
++					  entry->lines);
++
++			/* failed to find one */
++			if (!line) {
++				notSuitablePrintf(entry, 0, "no line found\n");
++				return 0;
++			}
+ 
+-	    for (i = 1; i < line->numElements; i++) 
+-	        if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
+-	    if (i < line->numElements)
+-	        dev = line->elements[i].item + 5;
+-	    else {
+-		notSuitablePrintf(entry, 0, "no root= entry found\n");
+-		/* it failed too...  can't find root= */
+-	        return 0;
+-            }
++			for (i = 1; i < line->numElements; i++)
++				if (!strncasecmp
++				    (line->elements[i].item, "root=", 5))
++					break;
++			if (i < line->numElements)
++				dev = line->elements[i].item + 5;
++			else {
++				notSuitablePrintf(entry, 0,
++						  "no root= entry found\n");
++				/* it failed too...  can't find root= */
++				return 0;
++			}
++		}
+ 	}
+-    }
+ 
+-    dev = getpathbyspec(dev);
+-    if (!getpathbyspec(dev)) {
+-        notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
+-        return 0;
+-    } else
+ 	dev = getpathbyspec(dev);
++	if (!getpathbyspec(dev)) {
++		notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n",
++				  dev);
++		return 0;
++	} else
++		dev = getpathbyspec(dev);
+ 
+-    rootdev = findDiskForRoot();
+-    if (!rootdev) {
+-        notSuitablePrintf(entry, 0, "can't find root device\n");
+-	return 0;
+-    }
++	rootdev = findDiskForRoot();
++	if (!rootdev) {
++		notSuitablePrintf(entry, 0, "can't find root device\n");
++		return 0;
++	}
+ 
+-    if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
+-        notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
+-		getuuidbydev(rootdev), getuuidbydev(dev));
+-        free(rootdev);
+-        return 0;
+-    }
++	if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
++		notSuitablePrintf(entry, 0,
++				  "uuid missing: rootdev %s, dev %s\n",
++				  getuuidbydev(rootdev), getuuidbydev(dev));
++		free(rootdev);
++		return 0;
++	}
++
++	if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
++		notSuitablePrintf(entry, 0,
++				  "uuid mismatch: rootdev %s, dev %s\n",
++				  getuuidbydev(rootdev), getuuidbydev(dev));
++		free(rootdev);
++		return 0;
++	}
+ 
+-    if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
+-        notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
+-		getuuidbydev(rootdev), getuuidbydev(dev));
+ 	free(rootdev);
+-        return 0;
+-    }
++	notSuitablePrintf(entry, 1, "\n");
+ 
+-    free(rootdev);
+-    notSuitablePrintf(entry, 1, "\n");
+-
+-    return 1;
++	return 1;
+ }
+ 
+ /* returns the first match on or after the one pointed to by index (if index 
+    is not NULL) which is not marked as skip */
+-struct singleEntry * findEntryByPath(struct grubConfig * config, 
+-				     const char * kernel, const char * prefix,
+-				     int * index) {
+-    struct singleEntry * entry = NULL;
+-    struct singleLine * line;
+-    int i;
+-    char * chptr;
+-    char * rootspec = NULL;
+-    enum lineType_e checkType = LT_KERNEL;
+-
+-    if (isdigit(*kernel)) {
+-	int * indexVars = alloca(sizeof(*indexVars) * strlen(kernel));
+-
+-	i = 0;
+-	indexVars[i] = strtol(kernel, &chptr, 10);
+-	while (*chptr == ',') {
+-	    i++;
+-	    kernel = chptr + 1;
+-	    indexVars[i] = strtol(kernel, &chptr, 10);
+-	}
++struct singleEntry *findEntryByPath(struct grubConfig *config,
++				    const char *kernel, const char *prefix,
++				    int *index)
++{
++	struct singleEntry *entry = NULL;
++	struct singleLine *line;
++	int i;
++	char *chptr;
++	char *rootspec = NULL;
++	enum lineType_e checkType = LT_KERNEL;
+ 
+-	if (*chptr) {
+-	    /* can't parse it, bail */
+-	    return NULL;
+-	}
++	if (isdigit(*kernel)) {
++		int *indexVars = alloca(sizeof(*indexVars) * strlen(kernel));
++
++		i = 0;
++		indexVars[i] = strtol(kernel, &chptr, 10);
++		while (*chptr == ',') {
++			i++;
++			kernel = chptr + 1;
++			indexVars[i] = strtol(kernel, &chptr, 10);
++		}
++
++		if (*chptr) {
++			/* can't parse it, bail */
++			return NULL;
++		}
++
++		indexVars[i + 1] = -1;
++
++		i = 0;
++		if (index) {
++			while (i < *index) {
++				i++;
++				if (indexVars[i] == -1)
++					return NULL;
++			}
++		}
++
++		entry = findEntryByIndex(config, indexVars[i]);
++		if (!entry)
++			return NULL;
+ 
+-	indexVars[i + 1] = -1;
++		line =
++		    getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI |
++				  LT_KERNEL_16, entry->lines);
++		if (!line)
++			return NULL;
+ 
+-	i = 0;
+-	if (index) {
+-	    while (i < *index) {
+-		i++;
+-		if (indexVars[i] == -1) return NULL;
+-	    }
++		if (index)
++			*index = indexVars[i];
++		return entry;
+ 	}
+ 
+-	entry = findEntryByIndex(config, indexVars[i]);
+-	if (!entry) return NULL;
++	if (!strcmp(kernel, "DEFAULT")) {
++		if (index && *index > config->defaultImage) {
++			entry = NULL;
++		} else {
++			entry = findEntryByIndex(config, config->defaultImage);
++			if (entry && entry->skip)
++				entry = NULL;
++			else if (index)
++				*index = config->defaultImage;
++		}
++	} else if (!strcmp(kernel, "ALL")) {
++		if (index)
++			i = *index;
++		else
++			i = 0;
+ 
+-	line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
+-	if (!line) return NULL;
++		while ((entry = findEntryByIndex(config, i))) {
++			if (!entry->skip)
++				break;
++			i++;
++		}
+ 
+-	if (index) *index = indexVars[i];
+-	return entry;
+-    }
+-    
+-    if (!strcmp(kernel, "DEFAULT")) {
+-	if (index && *index > config->defaultImage) {
+-	    entry = NULL;
++		if (entry && index)
++			*index = i;
+ 	} else {
+-	    entry = findEntryByIndex(config, config->defaultImage);
+-	    if (entry && entry->skip) 
+-		entry = NULL;
+-	    else if (index) 
+-		*index = config->defaultImage;
+-	}
+-    } else if (!strcmp(kernel, "ALL")) {
+-	if (index)
+-	    i = *index;
+-	else
+-	    i = 0;
+-
+-	while ((entry = findEntryByIndex(config, i))) {
+-	    if (!entry->skip) break;
+-	    i++;
+-	}
++		if (index)
++			i = *index;
++		else
++			i = 0;
++
++		if (!strncmp(kernel, "TITLE=", 6)) {
++			prefix = "";
++			checkType = LT_TITLE | LT_MENUENTRY;
++			kernel += 6;
++		}
++
++		for (entry = findEntryByIndex(config, i); entry;
++		     entry = entry->next, i++) {
++			if (entry->skip)
++				continue;
++
++			dbgPrintf("findEntryByPath looking for %d %s in %p\n",
++				  checkType, kernel, entry);
+ 
+-	if (entry && index)
+-	    *index = i;
+-    } else {
+-	if (index)
+-	    i = *index;
+-	else
+-	    i = 0;
+-
+-	if (!strncmp(kernel, "TITLE=", 6)) {
+-	    prefix = "";
+-	    checkType = LT_TITLE|LT_MENUENTRY;
+-	    kernel += 6;
++			/* check all the lines matching checkType */
++			for (line = entry->lines; line; line = line->next) {
++				enum lineType_e ct = checkType;
++				if (entry->multiboot && checkType == LT_KERNEL)
++					ct = LT_KERNEL | LT_KERNEL_EFI |
++					    LT_MBMODULE | LT_HYPER |
++					    LT_KERNEL_16;
++				else if (checkType & LT_KERNEL)
++					ct = checkType | LT_KERNEL_EFI |
++					    LT_KERNEL_16;
++				line = getLineByType(ct, line);
++				if (!line)
++					break;	/* not found in this entry */
++
++				if (line && line->type != LT_MENUENTRY &&
++				    line->numElements >= 2) {
++					rootspec =
++					    getRootSpecifier(line->elements[1].
++							     item);
++					if (!strcmp
++					    (line->elements[1].item +
++					     ((rootspec !=
++					       NULL) ? strlen(rootspec) : 0),
++					     kernel + strlen(prefix)))
++						break;
++				}
++				if (line->type == LT_MENUENTRY &&
++				    !strcmp(line->elements[1].item, kernel))
++					break;
++			}
++
++			/* make sure this entry has a kernel identifier; this skips
++			 * non-Linux boot entries (could find netbsd etc, though, which is
++			 * unfortunate)
++			 */
++			if (line
++			    && getLineByType(LT_KERNEL | LT_HYPER |
++					     LT_KERNEL_EFI | LT_KERNEL_16,
++					     entry->lines))
++				break;	/* found 'im! */
++		}
++
++		if (index)
++			*index = i;
+ 	}
+ 
+-	for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
+-	    if (entry->skip) continue;
++	return entry;
++}
+ 
+-	    dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
++struct singleEntry *findEntryByTitle(struct grubConfig *cfg, char *title,
++				     int *index)
++{
++	struct singleEntry *entry;
++	struct singleLine *line;
++	int i;
++	char *newtitle;
+ 
+-	    /* check all the lines matching checkType */
+-	    for (line = entry->lines; line; line = line->next) {
+-		enum lineType_e ct = checkType;
+-		if (entry->multiboot && checkType == LT_KERNEL)
+-		    ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
+-		else if (checkType & LT_KERNEL)
+-		    ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
+-		line = getLineByType(ct, line);
++	for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
++		if (index && i < *index)
++			continue;
++		line = getLineByType(LT_TITLE, entry->lines);
++		if (!line)
++			line = getLineByType(LT_MENUENTRY, entry->lines);
+ 		if (!line)
+-		    break;  /* not found in this entry */
+-
+-		if (line && line->type != LT_MENUENTRY &&
+-			line->numElements >= 2) {
+-		    rootspec = getRootSpecifier(line->elements[1].item);
+-		    if (!strcmp(line->elements[1].item + 
+-				((rootspec != NULL) ? strlen(rootspec) : 0),
+-				kernel + strlen(prefix)))
++			continue;
++		newtitle = grub2ExtractTitle(line);
++		if (!newtitle)
++			continue;
++		if (!strcmp(title, newtitle))
+ 			break;
+-		}
+-		if(line->type == LT_MENUENTRY &&
+-			!strcmp(line->elements[1].item, kernel))
+-		    break;
+-	    }
+-
+-	    /* make sure this entry has a kernel identifier; this skips
+-	     * non-Linux boot entries (could find netbsd etc, though, which is
+-	     * unfortunate)
+-	     */
+-	    if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
+-		break; /* found 'im! */
+ 	}
+ 
+-	if (index) *index = i;
+-    }
++	if (!entry)
++		return NULL;
+ 
+-    return entry;
++	if (index)
++		*index = i;
++	return entry;
+ }
+ 
+-struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
+-				      int * index) {
+-    struct singleEntry * entry;
+-    struct singleLine * line;
+-    int i;
+-    char * newtitle;
+-
+-    for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
+-	if (index && i < *index)
+-	    continue;
+-	line = getLineByType(LT_TITLE, entry->lines);
+-	if (!line)
+-	    line = getLineByType(LT_MENUENTRY, entry->lines);
+-	if (!line)
+-	    continue;
+-	newtitle = grub2ExtractTitle(line);
+-	if (!newtitle)
+-	    continue;
+-	if (!strcmp(title, newtitle))
+-	    break;
+-    }
++struct singleEntry *findEntryByIndex(struct grubConfig *cfg, int index)
++{
++	struct singleEntry *entry;
+ 
+-    if (!entry)
+-	return NULL;
+-
+-    if (index)
+-	*index = i;
+-    return entry;
+-}
+-
+-struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
+-    struct singleEntry * entry;
+-
+-    entry = cfg->entries;
+-    while (index && entry) {
+-	entry = entry->next;
+-	index--;
+-    }
++	entry = cfg->entries;
++	while (index && entry) {
++		entry = entry->next;
++		index--;
++	}
+ 
+-    return entry;
++	return entry;
+ }
+ 
+ /* Find a good template to use for the new kernel. An entry is
+@@ -2149,2595 +2312,2886 @@ struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
+  * is going to be removed). Try and use the default entry, but
+  * if that doesn't work just take the first. If we can't find one,
+  * bail. */
+-struct singleEntry * findTemplate(struct grubConfig * cfg, const char * prefix,
+-				 int * indexPtr, int skipRemoved, int flags) {
+-    struct singleEntry * entry, * entry2;
+-    int index;
++struct singleEntry *findTemplate(struct grubConfig *cfg, const char *prefix,
++				 int *indexPtr, int skipRemoved, int flags)
++{
++	struct singleEntry *entry, *entry2;
++	int index;
+ 
+-    if (cfg->cfi->defaultIsSaved) {
+-	if (cfg->cfi->getEnv) {
+-	    char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
+-	    if (defTitle) {
+-		int index = 0;
+-		if (isnumber(defTitle)) {
+-		    index = atoi(defTitle);
+-		    entry = findEntryByIndex(cfg, index);
+-		} else {
+-		    entry = findEntryByTitle(cfg, defTitle, &index);
++	if (cfg->cfi->defaultIsSaved) {
++		if (cfg->cfi->getEnv) {
++			char *defTitle =
++			    cfg->cfi->getEnv(cfg->cfi, "saved_entry");
++			if (defTitle) {
++				int index = 0;
++				if (isnumber(defTitle)) {
++					index = atoi(defTitle);
++					entry = findEntryByIndex(cfg, index);
++				} else {
++					entry =
++					    findEntryByTitle(cfg, defTitle,
++							     &index);
++				}
++				if (entry
++				    && suitableImage(entry, prefix, skipRemoved,
++						     flags)) {
++					cfg->defaultImage = index;
++					if (indexPtr)
++						*indexPtr = index;
++					return entry;
++				}
++			}
+ 		}
++	} else if (cfg->defaultImage > -1) {
++		entry = findEntryByIndex(cfg, cfg->defaultImage);
+ 		if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
+-		    cfg->defaultImage = index;
+-		    if (indexPtr)
+-			*indexPtr = index;
+-		    return entry;
++			if (indexPtr)
++				*indexPtr = cfg->defaultImage;
++			return entry;
+ 		}
+-	    }
+-	}
+-    } else if (cfg->defaultImage > -1) {
+-	entry = findEntryByIndex(cfg, cfg->defaultImage);
+-	if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
+-	    if (indexPtr) *indexPtr = cfg->defaultImage;
+-	    return entry;
+-	}
+-    }
+-
+-    index = 0;
+-    while ((entry = findEntryByIndex(cfg, index))) {
+-	if (suitableImage(entry, prefix, skipRemoved, flags)) {
+-            int j;
+-            for (j = 0; j < index; j++) {
+-                entry2 = findEntryByIndex(cfg, j);
+-                if (entry2->skip) index--;
+-            }
+-	    if (indexPtr) *indexPtr = index;
+-
+-	    return entry;
+ 	}
+ 
+-	index++;
+-    }
++	index = 0;
++	while ((entry = findEntryByIndex(cfg, index))) {
++		if (suitableImage(entry, prefix, skipRemoved, flags)) {
++			int j;
++			for (j = 0; j < index; j++) {
++				entry2 = findEntryByIndex(cfg, j);
++				if (entry2->skip)
++					index--;
++			}
++			if (indexPtr)
++				*indexPtr = index;
++
++			return entry;
++		}
++
++		index++;
++	}
+ 
+-    fprintf(stderr, _("grubby fatal error: unable to find a suitable template\n"));
++	fprintf(stderr,
++		_("grubby fatal error: unable to find a suitable template\n"));
+ 
+-    return NULL;
++	return NULL;
+ }
+ 
+-char * findBootPrefix(void) {
+-    struct stat sb, sb2;
++char *findBootPrefix(void)
++{
++	struct stat sb, sb2;
+ 
+-    stat("/", &sb);
++	stat("/", &sb);
+ #ifdef __ia64__
+-    stat("/boot/efi/EFI/redhat/", &sb2);
++	stat("/boot/efi/EFI/redhat/", &sb2);
+ #else
+-    stat("/boot", &sb2);
++	stat("/boot", &sb2);
+ #endif
+ 
+-    if (sb.st_dev == sb2.st_dev)
+-	return strdup("");
++	if (sb.st_dev == sb2.st_dev)
++		return strdup("");
+ 
+ #ifdef __ia64__
+-    return strdup("/boot/efi/EFI/redhat/");
++	return strdup("/boot/efi/EFI/redhat/");
+ #else
+-    return strdup("/boot");
++	return strdup("/boot");
+ #endif
+ }
+ 
+-void markRemovedImage(struct grubConfig * cfg, const char * image, 
+-		      const char * prefix) {
+-    struct singleEntry * entry;
++void markRemovedImage(struct grubConfig *cfg, const char *image,
++		      const char *prefix)
++{
++	struct singleEntry *entry;
+ 
+-    if (!image)
+-	return;
++	if (!image)
++		return;
+ 
+-    /* check and see if we're removing the default image */
+-    if (isdigit(*image)) {
+-	entry = findEntryByPath(cfg, image, prefix, NULL);
+-	if(entry)
+-	    entry->skip = 1;
+-	return;
+-    }
++	/* check and see if we're removing the default image */
++	if (isdigit(*image)) {
++		entry = findEntryByPath(cfg, image, prefix, NULL);
++		if (entry)
++			entry->skip = 1;
++		return;
++	}
+ 
+-    while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
+-	entry->skip = 1;
++	while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
++		entry->skip = 1;
+ }
+ 
+-void setDefaultImage(struct grubConfig * config, int hasNew, 
+-		     const char * defaultKernelPath, int newIsDefault,
+-		     const char * prefix, int flags, int index) {
+-    struct singleEntry * entry, * entry2, * newDefault;
+-    int i, j;
+-
+-    if (newIsDefault) {
+-	config->defaultImage = 0;
+-	return;
+-    } else if ((index >= 0) && config->cfi->defaultIsIndex) {
+-	if (findEntryByIndex(config, index))
+-	    config->defaultImage = index;
++void setDefaultImage(struct grubConfig *config, int hasNew,
++		     const char *defaultKernelPath, int newIsDefault,
++		     const char *prefix, int flags, int index)
++{
++	struct singleEntry *entry, *entry2, *newDefault;
++	int i, j;
++
++	if (newIsDefault) {
++		config->defaultImage = 0;
++		return;
++	} else if ((index >= 0) && config->cfi->defaultIsIndex) {
++		if (findEntryByIndex(config, index))
++			config->defaultImage = index;
++		else
++			config->defaultImage = -1;
++		return;
++	} else if (defaultKernelPath) {
++		i = 0;
++		if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
++			config->defaultImage = i;
++		} else {
++			config->defaultImage = -1;
++			return;
++		}
++	}
++
++	/* defaultImage now points to what we'd like to use, but before any
++	 * order changes */
++	if ((config->defaultImage == DEFAULT_SAVED) ||
++	    (config->defaultImage == DEFAULT_SAVED_GRUB2))
++		/* default is set to saved, we don't want to change it */
++		return;
++
++	if (config->defaultImage > -1)
++		entry = findEntryByIndex(config, config->defaultImage);
+ 	else
+-	    config->defaultImage = -1;
+-	return;
+-    } else if (defaultKernelPath) {
+-	i = 0;
+-	if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
+-	    config->defaultImage = i;
++		entry = NULL;
++
++	if (entry && !entry->skip) {
++		/* we can preserve the default */
++		if (hasNew)
++			config->defaultImage++;
++
++		/* count the number of entries erased before this one */
++		for (j = 0; j < config->defaultImage; j++) {
++			entry2 = findEntryByIndex(config, j);
++			if (entry2->skip)
++				config->defaultImage--;
++		}
++	} else if (hasNew) {
++		config->defaultImage = 0;
+ 	} else {
+-	    config->defaultImage = -1;
+-	    return;
++		/* Either we just erased the default (or the default line was
++		 * bad to begin with) and didn't put a new one in. We'll use
++		 * the first valid image. */
++		newDefault =
++		    findTemplate(config, prefix, &config->defaultImage, 1,
++				 flags);
++		if (!newDefault)
++			config->defaultImage = -1;
+ 	}
+-    } 
++}
+ 
+-    /* defaultImage now points to what we'd like to use, but before any order 
+-       changes */
+-    if ((config->defaultImage == DEFAULT_SAVED) ||
+-	(config->defaultImage == DEFAULT_SAVED_GRUB2))
+-      /* default is set to saved, we don't want to change it */
+-      return;
++void setFallbackImage(struct grubConfig *config, int hasNew)
++{
++	struct singleEntry *entry, *entry2;
++	int j;
+ 
+-    if (config->defaultImage > -1) 
+-	entry = findEntryByIndex(config, config->defaultImage);
+-    else
+-	entry = NULL;
++	if (config->fallbackImage == -1)
++		return;
++
++	entry = findEntryByIndex(config, config->fallbackImage);
++	if (!entry || entry->skip) {
++		config->fallbackImage = -1;
++		return;
++	}
+ 
+-    if (entry && !entry->skip) {
+-	/* we can preserve the default */
+ 	if (hasNew)
+-	    config->defaultImage++;
+-	
++		config->fallbackImage++;
++
+ 	/* count the number of entries erased before this one */
+-	for (j = 0; j < config->defaultImage; j++) {
+-	    entry2 = findEntryByIndex(config, j);
+-	    if (entry2->skip) config->defaultImage--;
++	for (j = 0; j < config->fallbackImage; j++) {
++		entry2 = findEntryByIndex(config, j);
++		if (entry2->skip)
++			config->fallbackImage--;
+ 	}
+-    } else if (hasNew) {
+-	config->defaultImage = 0;
+-    } else {
+-	/* Either we just erased the default (or the default line was bad
+-	 * to begin with) and didn't put a new one in. We'll use the first
+-	 * valid image. */
+-	newDefault = findTemplate(config, prefix, &config->defaultImage, 1,
+-				  flags);
+-	if (!newDefault)
+-	    config->defaultImage = -1;
+-    }
+ }
+ 
+-void setFallbackImage(struct grubConfig * config, int hasNew) {
+-    struct singleEntry * entry, * entry2;
+-    int j;
+-
+-    if (config->fallbackImage == -1) return;
+-
+-    entry = findEntryByIndex(config, config->fallbackImage);
+-    if (!entry || entry->skip) {
+-	config->fallbackImage = -1;
+-	return;
+-    }
+-
+-    if (hasNew)
+-	config->fallbackImage++;
+-    
+-    /* count the number of entries erased before this one */
+-    for (j = 0; j < config->fallbackImage; j++) {
+-	entry2 = findEntryByIndex(config, j);
+-	if (entry2->skip) config->fallbackImage--;
+-    }
+-}
+-
+-void displayEntry(struct singleEntry * entry, const char * prefix, int index) {
+-    struct singleLine * line;
+-    char * root = NULL;
+-    int i;
+-    int j;
+-
+-    printf("index=%d\n", index);
+-
+-    line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
+-    if (!line) {
+-        printf("non linux entry\n");
+-        return;
+-    }
+-
+-    if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
+-	printf("kernel=%s\n", line->elements[1].item);
+-    else
+-	printf("kernel=%s%s\n", prefix, line->elements[1].item);
+-
+-    if (line->numElements >= 3) {
+-	printf("args=\"");
+-	i = 2;
+-	while (i < line->numElements) {
+-	    if (!strncmp(line->elements[i].item, "root=", 5)) {
+-		root = line->elements[i].item + 5;
+-	    } else {
+-		printf("%s%s", line->elements[i].item, 
+-			       line->elements[i].indent);
+-	    }
+-
+-	    i++;
++void displayEntry(struct singleEntry *entry, const char *prefix, int index)
++{
++	struct singleLine *line;
++	char *root = NULL;
++	int i;
++	int j;
++
++	printf("index=%d\n", index);
++
++	line =
++	    getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI | LT_KERNEL_16,
++			  entry->lines);
++	if (!line) {
++		printf("non linux entry\n");
++		return;
+ 	}
+-	printf("\"\n");
+-    } else {
+-	line = getLineByType(LT_KERNELARGS, entry->lines);
+-	if (line) {
+-	    char * s;
+-
+-	    printf("args=\"");
+-	    i = 1;
+-	    while (i < line->numElements) {
+-		if (!strncmp(line->elements[i].item, "root=", 5)) {
+-		    root = line->elements[i].item + 5;
+-		} else {
+-		    s = line->elements[i].item;
+-
+-		    printf("%s%s", s, line->elements[i].indent);
+-		}
+-
+-		i++;
+-	    }
+-
+-	    s = line->elements[i - 1].indent;
+-	    printf("\"\n");
+-	}
+-    }
+-
+-    if (!root) {
+-	line = getLineByType(LT_ROOT, entry->lines);
+-	if (line && line->numElements >= 2)
+-	    root=line->elements[1].item;
+-    }
+-
+-    if (root) {
+-	char * s = alloca(strlen(root) + 1);
+-	
+-	strcpy(s, root);
+-	if (s[strlen(s) - 1] == '"')
+-	    s[strlen(s) - 1] = '\0';
+-	/* make sure the root doesn't have a trailing " */
+-	printf("root=%s\n", s);
+-    }
+-
+-    line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
+ 
+-    if (line && line->numElements >= 2) {
+ 	if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
+-	    printf("initrd=");
++		printf("kernel=%s\n", line->elements[1].item);
+ 	else
+-	    printf("initrd=%s", prefix);
+-
+-	for (i = 1; i < line->numElements; i++)
+-	    printf("%s%s", line->elements[i].item, line->elements[i].indent);
+-	printf("\n");
+-    }
+-
+-    line = getLineByType(LT_TITLE, entry->lines);
+-    if (line) {
+-	printf("title=%s\n", line->elements[1].item);
+-    } else {
+-	char * title;
+-	line = getLineByType(LT_MENUENTRY, entry->lines);
++		printf("kernel=%s%s\n", prefix, line->elements[1].item);
++
++	if (line->numElements >= 3) {
++		printf("args=\"");
++		i = 2;
++		while (i < line->numElements) {
++			if (!strncmp(line->elements[i].item, "root=", 5)) {
++				root = line->elements[i].item + 5;
++			} else {
++				printf("%s%s", line->elements[i].item,
++				       line->elements[i].indent);
++			}
++
++			i++;
++		}
++		printf("\"\n");
++	} else {
++		line = getLineByType(LT_KERNELARGS, entry->lines);
++		if (line) {
++			char *s;
++
++			printf("args=\"");
++			i = 1;
++			while (i < line->numElements) {
++				if (!strncmp
++				    (line->elements[i].item, "root=", 5)) {
++					root = line->elements[i].item + 5;
++				} else {
++					s = line->elements[i].item;
++
++					printf("%s%s", s,
++					       line->elements[i].indent);
++				}
++
++				i++;
++			}
++
++			s = line->elements[i - 1].indent;
++			printf("\"\n");
++		}
++	}
++
++	if (!root) {
++		line = getLineByType(LT_ROOT, entry->lines);
++		if (line && line->numElements >= 2)
++			root = line->elements[1].item;
++	}
++
++	if (root) {
++		char *s = alloca(strlen(root) + 1);
++
++		strcpy(s, root);
++		if (s[strlen(s) - 1] == '"')
++			s[strlen(s) - 1] = '\0';
++		/* make sure the root doesn't have a trailing " */
++		printf("root=%s\n", s);
++	}
++
++	line =
++	    getLineByType(LT_INITRD | LT_INITRD_EFI | LT_INITRD_16,
++			  entry->lines);
++
++	if (line && line->numElements >= 2) {
++		if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
++			printf("initrd=");
++		else
++			printf("initrd=%s", prefix);
++
++		for (i = 1; i < line->numElements; i++)
++			printf("%s%s", line->elements[i].item,
++			       line->elements[i].indent);
++		printf("\n");
++	}
++
++	line = getLineByType(LT_TITLE, entry->lines);
+ 	if (line) {
+-	    title = grub2ExtractTitle(line);
+-	    if (title)
+-		printf("title=%s\n", title);
++		printf("title=%s\n", line->elements[1].item);
++	} else {
++		char *title;
++		line = getLineByType(LT_MENUENTRY, entry->lines);
++		if (line) {
++			title = grub2ExtractTitle(line);
++			if (title)
++				printf("title=%s\n", title);
++		}
+ 	}
+-    }
+-
+-    for (j = 0, line = entry->lines; line; line = line->next) {
+-	if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
+-	    if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
+-		printf("mbmodule%d=", j);
+-	    else
+-		printf("mbmodule%d=%s", j, prefix);
+-
+-	    for (i = 1; i < line->numElements; i++)
+-		printf("%s%s", line->elements[i].item, line->elements[i].indent);
+-	    printf("\n");
+-	    j++;
++
++	for (j = 0, line = entry->lines; line; line = line->next) {
++		if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
++			if (!strncmp
++			    (prefix, line->elements[1].item, strlen(prefix)))
++				printf("mbmodule%d=", j);
++			else
++				printf("mbmodule%d=%s", j, prefix);
++
++			for (i = 1; i < line->numElements; i++)
++				printf("%s%s", line->elements[i].item,
++				       line->elements[i].indent);
++			printf("\n");
++			j++;
++		}
+ 	}
+-    }
+ }
+ 
+-int isSuseSystem(void) {
+-    const char * path;
+-    const static char default_path[] = "/etc/SuSE-release";
++int isSuseSystem(void)
++{
++	const char *path;
++	const static char default_path[] = "/etc/SuSE-release";
++
++	if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
++		path = default_path;
++
++	if (!access(path, R_OK))
++		return 1;
++	return 0;
++}
++
++int isSuseGrubConf(const char *path)
++{
++	FILE *grubConf;
++	char *line = NULL;
++	size_t len = 0, res = 0;
++
++	grubConf = fopen(path, "r");
++	if (!grubConf) {
++		dbgPrintf("Could not open SuSE configuration file '%s'\n",
++			  path);
++		return 0;
++	}
++
++	while ((res = getline(&line, &len, grubConf)) != -1) {
++		if (!strncmp(line, "setup", 5)) {
++			fclose(grubConf);
++			free(line);
++			return 1;
++		}
++	}
++
++	dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
++		  path);
++
++	fclose(grubConf);
++	free(line);
++	return 0;
++}
++
++int suseGrubConfGetLba(const char *path, int *lbaPtr)
++{
++	FILE *grubConf;
++	char *line = NULL;
++	size_t res = 0, len = 0;
++
++	if (!path)
++		return 1;
++	if (!lbaPtr)
++		return 1;
++
++	grubConf = fopen(path, "r");
++	if (!grubConf)
++		return 1;
++
++	while ((res = getline(&line, &len, grubConf)) != -1) {
++		if (line[res - 1] == '\n')
++			line[res - 1] = '\0';
++		else if (len > res)
++			line[res] = '\0';
++		else {
++			line = realloc(line, res + 1);
++			line[res] = '\0';
++		}
+ 
+-    if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
+-	path = default_path;
++		if (!strncmp(line, "setup", 5)) {
++			if (strstr(line, "--force-lba")) {
++				*lbaPtr = 1;
++			} else {
++				*lbaPtr = 0;
++			}
++			dbgPrintf("lba: %i\n", *lbaPtr);
++			break;
++		}
++	}
++
++	free(line);
++	fclose(grubConf);
++	return 0;
++}
++
++int suseGrubConfGetInstallDevice(const char *path, char **devicePtr)
++{
++	FILE *grubConf;
++	char *line = NULL;
++	size_t res = 0, len = 0;
++	char *lastParamPtr = NULL;
++	char *secLastParamPtr = NULL;
++	char installDeviceNumber = '\0';
++	char *bounds = NULL;
++
++	if (!path)
++		return 1;
++	if (!devicePtr)
++		return 1;
++
++	grubConf = fopen(path, "r");
++	if (!grubConf)
++		return 1;
++
++	while ((res = getline(&line, &len, grubConf)) != -1) {
++		if (strncmp(line, "setup", 5))
++			continue;
++
++		if (line[res - 1] == '\n')
++			line[res - 1] = '\0';
++		else if (len > res)
++			line[res] = '\0';
++		else {
++			line = realloc(line, res + 1);
++			line[res] = '\0';
++		}
++
++		lastParamPtr = bounds = line + res;
++
++		/* Last parameter in grub may be an optional IMAGE_DEVICE */
++		while (!isspace(*lastParamPtr))
++			lastParamPtr--;
++		lastParamPtr++;
++
++		secLastParamPtr = lastParamPtr - 2;
++		dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
++
++		if (lastParamPtr + 3 > bounds) {
++			dbgPrintf("lastParamPtr going over boundary");
++			fclose(grubConf);
++			free(line);
++			return 1;
++		}
++		if (!strncmp(lastParamPtr, "(hd", 3))
++			lastParamPtr += 3;
++		dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
++
++		/*
++		 * Second last parameter will decide wether last parameter is
++		 * an IMAGE_DEVICE or INSTALL_DEVICE
++		 */
++		while (!isspace(*secLastParamPtr))
++			secLastParamPtr--;
++		secLastParamPtr++;
++
++		if (secLastParamPtr + 3 > bounds) {
++			dbgPrintf("secLastParamPtr going over boundary");
++			fclose(grubConf);
++			free(line);
++			return 1;
++		}
++		dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
++		if (!strncmp(secLastParamPtr, "(hd", 3)) {
++			secLastParamPtr += 3;
++			dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
++			installDeviceNumber = *secLastParamPtr;
++		} else {
++			installDeviceNumber = *lastParamPtr;
++		}
++
++		*devicePtr = malloc(6);
++		snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
++		dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
++		fclose(grubConf);
++		free(line);
++		return 0;
++	}
+ 
+-    if (!access(path, R_OK))
++	free(line);
++	fclose(grubConf);
+ 	return 1;
+-    return 0;
+ }
+ 
+-int isSuseGrubConf(const char * path) {
+-    FILE * grubConf;
+-    char * line = NULL;
+-    size_t len = 0, res = 0;
+-
+-    grubConf = fopen(path, "r");
+-    if (!grubConf) {
+-        dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
+-	return 0;
+-    }
+-
+-    while ((res = getline(&line, &len, grubConf)) != -1) {
+-	if (!strncmp(line, "setup", 5)) {
+-	    fclose(grubConf);
+-	    free(line);
+-	    return 1;
+-	}
+-    }
+-
+-    dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
+-	      path);
+-
+-    fclose(grubConf);
+-    free(line);
+-    return 0;
+-}
+-
+-int suseGrubConfGetLba(const char * path, int * lbaPtr) {
+-    FILE * grubConf;
+-    char * line = NULL;
+-    size_t res = 0, len = 0;
+-
+-    if (!path) return 1;
+-    if (!lbaPtr) return 1;
+-
+-    grubConf = fopen(path, "r");
+-    if (!grubConf) return 1;
+-
+-    while ((res = getline(&line, &len, grubConf)) != -1) {
+-	if (line[res - 1] == '\n')
+-	    line[res - 1] = '\0';
+-	else if (len > res)
+-	    line[res] = '\0';
+-	else {
+-	    line = realloc(line, res + 1);
+-	    line[res] = '\0';
++int grubGetBootFromDeviceMap(const char *device, char **bootPtr)
++{
++	FILE *deviceMap;
++	char *line = NULL;
++	size_t res = 0, len = 0;
++	char *devicePtr;
++	char *bounds = NULL;
++	const char *path;
++	const static char default_path[] = "/boot/grub/device.map";
++
++	if (!device)
++		return 1;
++	if (!bootPtr)
++		return 1;
++
++	if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
++		path = default_path;
++
++	dbgPrintf("opening grub device.map file from: %s\n", path);
++	deviceMap = fopen(path, "r");
++	if (!deviceMap)
++		return 1;
++
++	while ((res = getline(&line, &len, deviceMap)) != -1) {
++		if (!strncmp(line, "#", 1))
++			continue;
++
++		if (line[res - 1] == '\n')
++			line[res - 1] = '\0';
++		else if (len > res)
++			line[res] = '\0';
++		else {
++			line = realloc(line, res + 1);
++			line[res] = '\0';
++		}
++
++		devicePtr = line;
++		bounds = line + res;
++
++		while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
++			devicePtr++;
++		dbgPrintf("device: %s\n", devicePtr);
++
++		if (!strncmp(devicePtr, device, strlen(device))) {
++			devicePtr += strlen(device);
++			while (isspace(*devicePtr)
++			       && ((devicePtr + 1) <= bounds))
++				devicePtr++;
++
++			*bootPtr = strdup(devicePtr);
++			break;
++		}
+ 	}
+ 
+-	if (!strncmp(line, "setup", 5)) {
+-	    if (strstr(line, "--force-lba")) {
+-	        *lbaPtr = 1;
+-	    } else {
+-	        *lbaPtr = 0;
+-	    }
+-	    dbgPrintf("lba: %i\n", *lbaPtr);
+-	    break;
+-	}
+-    }
+-
+-    free(line);
+-    fclose(grubConf);
+-    return 0;
++	free(line);
++	fclose(deviceMap);
++	return 0;
+ }
+ 
+-int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
+-    FILE * grubConf;
+-    char * line = NULL;
+-    size_t res = 0, len = 0;
+-    char * lastParamPtr = NULL;
+-    char * secLastParamPtr = NULL;
+-    char installDeviceNumber = '\0';
+-    char * bounds = NULL;
+-
+-    if (!path) return 1;
+-    if (!devicePtr) return 1;
+-
+-    grubConf = fopen(path, "r");
+-    if (!grubConf) return 1;
+-
+-    while ((res = getline(&line, &len, grubConf)) != -1) {
+-	if (strncmp(line, "setup", 5))
+-	    continue;
+-
+-	if (line[res - 1] == '\n')
+-	    line[res - 1] = '\0';
+-	else if (len > res)
+-	    line[res] = '\0';
+-	else {
+-	    line = realloc(line, res + 1);
+-	    line[res] = '\0';
+-	}
+-
+-	lastParamPtr = bounds = line + res;
++int suseGrubConfGetBoot(const char *path, char **bootPtr)
++{
++	char *grubDevice;
+ 
+-	/* Last parameter in grub may be an optional IMAGE_DEVICE */
+-	while (!isspace(*lastParamPtr))
+-	    lastParamPtr--;
+-	lastParamPtr++;
++	if (suseGrubConfGetInstallDevice(path, &grubDevice))
++		dbgPrintf("error looking for grub installation device\n");
++	else
++		dbgPrintf("grubby installation device: %s\n", grubDevice);
+ 
+-	secLastParamPtr = lastParamPtr - 2;
+-	dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
++	if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
++		dbgPrintf("error looking for grub boot device\n");
++	else
++		dbgPrintf("grubby boot device: %s\n", *bootPtr);
+ 
+-	if (lastParamPtr + 3 > bounds) {
+-	    dbgPrintf("lastParamPtr going over boundary");
+-	    fclose(grubConf);
+-	    free(line);
+-	    return 1;
+-	}
+-	if (!strncmp(lastParamPtr, "(hd", 3))
+-	    lastParamPtr += 3;
+-	dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
++	free(grubDevice);
++	return 0;
++}
+ 
++int parseSuseGrubConf(int *lbaPtr, char **bootPtr)
++{
+ 	/*
+-	 * Second last parameter will decide wether last parameter is
+-	 * an IMAGE_DEVICE or INSTALL_DEVICE
++	 * This SuSE grub configuration file at this location is not your
++	 * average grub configuration file, but instead the grub commands
++	 * used to setup grub on that system.
+ 	 */
+-	while (!isspace(*secLastParamPtr))
+-	    secLastParamPtr--;
+-	secLastParamPtr++;
+-
+-	if (secLastParamPtr + 3 > bounds) {
+-	    dbgPrintf("secLastParamPtr going over boundary");
+-	    fclose(grubConf);
+-	    free(line);
+-	    return 1;
+-	}
+-	dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
+-	if (!strncmp(secLastParamPtr, "(hd", 3)) {
+-	    secLastParamPtr += 3;
+-	    dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
+-	    installDeviceNumber = *secLastParamPtr;
+-	} else {
+-	    installDeviceNumber = *lastParamPtr;
+-	}
++	const char *path;
++	const static char default_path[] = "/etc/grub.conf";
+ 
+-	*devicePtr = malloc(6);
+-	snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
+-	dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
+-	fclose(grubConf);
+-	free(line);
+-	return 0;
+-    }
++	if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
++		path = default_path;
+ 
+-    free(line);
+-    fclose(grubConf);
+-    return 1;
+-}
++	if (!isSuseGrubConf(path))
++		return 1;
+ 
+-int grubGetBootFromDeviceMap(const char * device,
+-			     char ** bootPtr) {
+-    FILE * deviceMap;
+-    char * line = NULL;
+-    size_t res = 0, len = 0;
+-    char * devicePtr;
+-    char * bounds = NULL;
+-    const char * path;
+-    const static char default_path[] = "/boot/grub/device.map";
+-
+-    if (!device) return 1;
+-    if (!bootPtr) return 1;
+-
+-    if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
+-	path = default_path;
+-
+-    dbgPrintf("opening grub device.map file from: %s\n", path);
+-    deviceMap = fopen(path, "r");
+-    if (!deviceMap)
+-	return 1;
+-
+-    while ((res = getline(&line, &len, deviceMap)) != -1) {
+-        if (!strncmp(line, "#", 1))
+-	    continue;
+-
+-	if (line[res - 1] == '\n')
+-	    line[res - 1] = '\0';
+-	else if (len > res)
+-	    line[res] = '\0';
+-	else {
+-	    line = realloc(line, res + 1);
+-	    line[res] = '\0';
++	if (lbaPtr) {
++		*lbaPtr = 0;
++		if (suseGrubConfGetLba(path, lbaPtr))
++			return 1;
+ 	}
+ 
+-	devicePtr = line;
+-	bounds = line + res;
+-
+-	while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
+-	    devicePtr++;
+-	dbgPrintf("device: %s\n", devicePtr);
+-
+-	if (!strncmp(devicePtr, device, strlen(device))) {
+-	    devicePtr += strlen(device);
+-	    while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
+-	        devicePtr++;
+-
+-	    *bootPtr = strdup(devicePtr);
+-	    break;
++	if (bootPtr) {
++		*bootPtr = NULL;
++		suseGrubConfGetBoot(path, bootPtr);
+ 	}
+-    }
+ 
+-    free(line);
+-    fclose(deviceMap);
+-    return 0;
++	return 0;
+ }
+ 
+-int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
+-    char * grubDevice;
+-
+-    if (suseGrubConfGetInstallDevice(path, &grubDevice))
+-	dbgPrintf("error looking for grub installation device\n");
+-    else
+-	dbgPrintf("grubby installation device: %s\n", grubDevice);
++int parseSysconfigGrub(int *lbaPtr, char **bootPtr)
++{
++	FILE *in;
++	char buf[1024];
++	char *chptr;
++	char *start;
++	char *param;
++
++	in = fopen("/etc/sysconfig/grub", "r");
++	if (!in)
++		return 1;
++
++	if (lbaPtr)
++		*lbaPtr = 0;
++	if (bootPtr)
++		*bootPtr = NULL;
++
++	while (fgets(buf, sizeof(buf), in)) {
++		start = buf;
++		while (isspace(*start))
++			start++;
++		if (*start == '#')
++			continue;
++
++		chptr = strchr(start, '=');
++		if (!chptr)
++			continue;
++		chptr--;
++		while (*chptr && isspace(*chptr))
++			chptr--;
++		chptr++;
++		*chptr = '\0';
++
++		param = chptr + 1;
++		while (*param && isspace(*param))
++			param++;
++		if (*param == '=') {
++			param++;
++			while (*param && isspace(*param))
++				param++;
++		}
++
++		chptr = param;
++		while (*chptr && !isspace(*chptr))
++			chptr++;
++		*chptr = '\0';
++
++		if (!strcmp(start, "forcelba") && !strcmp(param, "1") && lbaPtr)
++			*lbaPtr = 1;
++		else if (!strcmp(start, "boot") && bootPtr)
++			*bootPtr = strdup(param);
++	}
+ 
+-    if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
+-	dbgPrintf("error looking for grub boot device\n");
+-    else
+-	dbgPrintf("grubby boot device: %s\n", *bootPtr);
++	fclose(in);
+ 
+-    free(grubDevice);
+-    return 0;
++	return 0;
+ }
+ 
+-int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
+-    /*
+-     * This SuSE grub configuration file at this location is not your average
+-     * grub configuration file, but instead the grub commands used to setup
+-     * grub on that system.
+-     */
+-    const char * path;
+-    const static char default_path[] = "/etc/grub.conf";
+-
+-    if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
+-	path = default_path;
+-
+-    if (!isSuseGrubConf(path)) return 1;
+-
+-    if (lbaPtr) {
+-        *lbaPtr = 0;
+-        if (suseGrubConfGetLba(path, lbaPtr))
+-            return 1;
+-    }
++void dumpSysconfigGrub(void)
++{
++	char *boot = NULL;
++	int lba;
+ 
+-    if (bootPtr) {
+-        *bootPtr = NULL;
+-        suseGrubConfGetBoot(path, bootPtr);
+-    }
+-
+-    return 0;
+-}
+-
+-int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
+-    FILE * in;
+-    char buf[1024];
+-    char * chptr;
+-    char * start;
+-    char * param;
+-
+-    in = fopen("/etc/sysconfig/grub", "r");
+-    if (!in) return 1;
+-
+-    if (lbaPtr) *lbaPtr = 0;
+-    if (bootPtr) *bootPtr = NULL;
+-
+-    while (fgets(buf, sizeof(buf), in)) {
+-	start = buf;
+-	while (isspace(*start)) start++;
+-	if (*start == '#') continue;
+-
+-	chptr = strchr(start, '=');
+-	if (!chptr) continue;
+-	chptr--;
+-	while (*chptr && isspace(*chptr)) chptr--;
+-	chptr++;
+-	*chptr = '\0';
+-
+-	param = chptr + 1;
+-	while (*param && isspace(*param)) param++;
+-	if (*param == '=') {
+-	    param++;
+-	    while (*param && isspace(*param)) param++;
++	if (isSuseSystem()) {
++		if (parseSuseGrubConf(&lba, &boot)) {
++			free(boot);
++			return;
++		}
++	} else {
++		if (parseSysconfigGrub(&lba, &boot)) {
++			free(boot);
++			return;
++		}
+ 	}
+ 
+-	chptr = param;
+-	while (*chptr && !isspace(*chptr)) chptr++;
+-	*chptr = '\0';
+-
+-	if (!strcmp(start, "forcelba") && !strcmp(param, "1") && lbaPtr)
+-	    *lbaPtr = 1;
+-	else if (!strcmp(start, "boot") && bootPtr)
+-	    *bootPtr = strdup(param);
+-    }
+-
+-    fclose(in);
+-
+-    return 0;
++	if (lba)
++		printf("lba\n");
++	if (boot) {
++		printf("boot=%s\n", boot);
++		free(boot);
++	}
+ }
+ 
+-void dumpSysconfigGrub(void) {
+-    char * boot = NULL;
+-    int lba;
++int displayInfo(struct grubConfig *config, char *kernel, const char *prefix)
++{
++	int i = 0;
++	struct singleEntry *entry;
++	struct singleLine *line;
+ 
+-    if (isSuseSystem()) {
+-        if (parseSuseGrubConf(&lba, &boot)) {
+-	    free(boot);
+-	    return;
+-	}
+-    } else {
+-        if (parseSysconfigGrub(&lba, &boot)) {
+-	    free(boot);
+-	    return;
++	entry = findEntryByPath(config, kernel, prefix, &i);
++	if (!entry) {
++		fprintf(stderr, _("grubby: kernel not found\n"));
++		return 1;
+ 	}
+-    }
+-
+-    if (lba) printf("lba\n");
+-    if (boot) {
+-	printf("boot=%s\n", boot);
+-	free(boot);
+-    }
+-}
+ 
+-int displayInfo(struct grubConfig * config, char * kernel,
+-		const char * prefix) {
+-    int i = 0;
+-    struct singleEntry * entry;
+-    struct singleLine * line;
+-
+-    entry = findEntryByPath(config, kernel, prefix, &i);
+-    if (!entry) {
+-	fprintf(stderr, _("grubby: kernel not found\n"));
+-	return 1;
+-    }
+-
+-    /* this is a horrible hack to support /etc/sysconfig/grub; there must
+-       be a better way */
+-    if (config->cfi == &grubConfigType) {
+-	dumpSysconfigGrub();
+-    } else {
+-	line = getLineByType(LT_BOOT, config->theLines);
+-	if (line && line->numElements >= 1) {
+-	    printf("boot=%s\n", line->elements[1].item);
++	/* this is a horrible hack to support /etc/sysconfig/grub; there must
++	   be a better way */
++	if (config->cfi == &grubConfigType) {
++		dumpSysconfigGrub();
++	} else {
++		line = getLineByType(LT_BOOT, config->theLines);
++		if (line && line->numElements >= 1) {
++			printf("boot=%s\n", line->elements[1].item);
++		}
++
++		line = getLineByType(LT_LBA, config->theLines);
++		if (line)
++			printf("lba\n");
+ 	}
+ 
+-	line = getLineByType(LT_LBA, config->theLines);
+-	if (line) printf("lba\n");
+-    }
+-
+-    displayEntry(entry, prefix, i);
+-
+-    i++;
+-    while ((entry = findEntryByPath(config, kernel, prefix, &i))) {
+ 	displayEntry(entry, prefix, i);
++
+ 	i++;
+-    }
++	while ((entry = findEntryByPath(config, kernel, prefix, &i))) {
++		displayEntry(entry, prefix, i);
++		i++;
++	}
+ 
+-    return 0;
++	return 0;
+ }
+ 
+-struct singleLine * addLineTmpl(struct singleEntry * entry,
+-				struct singleLine * tmplLine,
+-				struct singleLine * prevLine,
+-				const char * val,
+-				struct configFileInfo * cfi)
++struct singleLine *addLineTmpl(struct singleEntry *entry,
++			       struct singleLine *tmplLine,
++			       struct singleLine *prevLine,
++			       const char *val, struct configFileInfo *cfi)
+ {
+-    struct singleLine * newLine = lineDup(tmplLine);
++	struct singleLine *newLine = lineDup(tmplLine);
+ 
+-    if (isEfi && cfi == &grub2ConfigType) {
+-	enum lineType_e old = newLine->type;
+-	newLine->type = preferredLineType(newLine->type, cfi);
+-	if (old != newLine->type)
+-	    newLine->elements[0].item = getKeyByType(newLine->type, cfi);
+-    }
+-
+-    if (val) {
+-	/* override the inherited value with our own.
+-	 * This is a little weak because it only applies to elements[1]
+-	 */
+-	if (newLine->numElements > 1)
+-	    removeElement(newLine, 1);
+-	insertElement(newLine, val, 1, cfi);
+-
+-	/* but try to keep the rootspec from the template... sigh */
+-	if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
+-	    char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
+-	    if (rootspec != NULL) {
+-		free(newLine->elements[1].item);
+-		newLine->elements[1].item = 
+-		    sdupprintf("%s%s", rootspec, val);
+-	    }
++	if (isEfi && cfi == &grub2ConfigType) {
++		enum lineType_e old = newLine->type;
++		newLine->type = preferredLineType(newLine->type, cfi);
++		if (old != newLine->type)
++			newLine->elements[0].item =
++			    getKeyByType(newLine->type, cfi);
+ 	}
+-    }
+-
+-    dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ? 
+-	      newLine->elements[0].item : "");
+-
+-    if (!entry->lines) {
+-	/* first one on the list */
+-	entry->lines = newLine;
+-    } else if (prevLine) {
+-	/* add after prevLine */
+-	newLine->next = prevLine->next;
+-	prevLine->next = newLine;
+-    }
+-
+-    return newLine;
+-}
+ 
+-/* val may be NULL */
+-struct singleLine *  addLine(struct singleEntry * entry, 
+-			     struct configFileInfo * cfi, 
+-			     enum lineType_e type, char * defaultIndent,
+-			     const char * val) {
+-    struct singleLine * line, * prev;
+-    struct keywordTypes * kw;
+-    struct singleLine tmpl;
+-
+-    /* NB: This function shouldn't allocate items on the heap, rather on the
+-     * stack since it calls addLineTmpl which will make copies.
+-     */
+-    if (type == LT_TITLE && cfi->titleBracketed) {
+-	/* we're doing a bracketed title (zipl) */
+-	tmpl.type = type;
+-	tmpl.numElements = 1;
+-	tmpl.elements = alloca(sizeof(*tmpl.elements));
+-	tmpl.elements[0].item = alloca(strlen(val)+3);
+-	sprintf(tmpl.elements[0].item, "[%s]", val);
+-	tmpl.elements[0].indent = "";
+-	val = NULL;
+-    } else if (type == LT_MENUENTRY) {
+-	char *lineend = "--class gnu-linux --class gnu --class os {";
+-	if (!val) {
+-	    fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
+-	    abort();
+-	}
+-	kw = getKeywordByType(type, cfi);
+-	if (!kw) {
+-	    fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
+-	    abort();
+-	}
+-	tmpl.indent = "";
+-	tmpl.type = type;
+-	tmpl.numElements = 3;
+-	tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
+-	tmpl.elements[0].item = kw->key;
+-	tmpl.elements[0].indent = alloca(2);
+-	sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
+-	tmpl.elements[1].item = (char *)val;
+-	tmpl.elements[1].indent = alloca(2);
+-	sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
+-	tmpl.elements[2].item = alloca(strlen(lineend)+1);
+-	strcpy(tmpl.elements[2].item, lineend);
+-	tmpl.elements[2].indent = "";
+-    } else {
+-	kw = getKeywordByType(type, cfi);
+-	if (!kw) {
+-	    fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
+-	    abort();
+-	}
+-	tmpl.type = type;
+-	tmpl.numElements = val ? 2 : 1;
+-	tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
+-	tmpl.elements[0].item = kw->key;
+-	tmpl.elements[0].indent = alloca(2);
+-	sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
+ 	if (val) {
+-	    tmpl.elements[1].item = (char *)val;
+-	    tmpl.elements[1].indent = "";
+-	}
+-    }
+-
+-    /* The last non-empty line gives us the indention to us and the line
+-       to insert after. Note that comments are considered empty lines, which
+-       may not be ideal? If there are no lines or we are looking at the
+-       first line, we use defaultIndent (the first line is normally indented
+-       differently from the rest) */ 
+-    for (line = entry->lines, prev = NULL; line; line = line->next) {
+-	if (line->numElements) prev = line;
+-	/* fall back on the last line if prev isn't otherwise set */
+-	if (!line->next && !prev) prev = line;
+-    }
+-
+-    struct singleLine *menuEntry;
+-    menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
+-    if (tmpl.type == LT_ENTRY_END) {
+-	if (menuEntry)
+-	    tmpl.indent = menuEntry->indent;
+-	else
+-	    tmpl.indent = defaultIndent ?: "";
+-    } else if (tmpl.type != LT_MENUENTRY) {
+-	if (menuEntry)
+-	    tmpl.indent = "\t";
+-	else if (prev == entry->lines)
+-	    tmpl.indent = defaultIndent ?: "";
+-	else
+-	    tmpl.indent = prev->indent;
+-    }
+-
+-    return addLineTmpl(entry, &tmpl, prev, val, cfi);
+-}
+-
+-void removeLine(struct singleEntry * entry, struct singleLine * line) {
+-    struct singleLine * prev;
+-    int i;
+-
+-    for (i = 0; i < line->numElements; i++) {
+-	free(line->elements[i].item);
+-	free(line->elements[i].indent);
+-    }
+-    free(line->elements);
+-    free(line->indent);
+-
+-    if (line == entry->lines) {
+-	entry->lines = line->next;
+-    } else {
+-	prev = entry->lines;
+-	while (prev->next != line) prev = prev->next;
+-	prev->next = line->next;
+-    }
+-
+-    free(line);
+-}
+-
+-static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
+-{
+-    struct singleLine newLine = {
+-	.indent = tmplLine->indent,
+-	.type = tmplLine->type,
+-	.next = tmplLine->next,
+-    };
+-    int firstQuotedItem = -1;
+-    int quoteLen = 0;
+-    int j;
+-    int element = 0;
+-    char *c;
+-
+-    c = malloc(strlen(tmplLine->elements[0].item) + 1);
+-    strcpy(c, tmplLine->elements[0].item);
+-    insertElement(&newLine, c, element++, cfi);
+-    free(c);
+-    c = NULL;
+-
+-    for (j = 1; j < tmplLine->numElements; j++) {
+-	if (firstQuotedItem == -1) {
+-	    quoteLen += strlen(tmplLine->elements[j].item);
+-	    
+-	    if (isquote(tmplLine->elements[j].item[0])) {
+-		firstQuotedItem = j;
+-	        quoteLen += strlen(tmplLine->elements[j].indent);
+-	    } else {
+-		c = malloc(quoteLen + 1);
+-		strcpy(c, tmplLine->elements[j].item);
+-		insertElement(&newLine, c, element++, cfi);
+-		free(c);
+-		quoteLen = 0;
+-	    }
+-	} else {
+-	    int itemlen = strlen(tmplLine->elements[j].item);
+-	    quoteLen += itemlen;
+-	    quoteLen += strlen(tmplLine->elements[j].indent);
+-	    
+-	    if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
+-		c = malloc(quoteLen + 1);
+-		c[0] = '\0';
+-		for (int i = firstQuotedItem; i < j+1; i++) {
+-		    strcat(c, tmplLine->elements[i].item);
+-		    strcat(c, tmplLine->elements[i].indent);
+-		}
+-		insertElement(&newLine, c, element++, cfi);
+-		free(c);
+-		
+-		firstQuotedItem = -1;
+-		quoteLen = 0;
+-	    }
+-	}
+-    }
+-    while (tmplLine->numElements)
+-	removeElement(tmplLine, 0);
+-    if (tmplLine->elements)
+-	free(tmplLine->elements);
+-
+-    tmplLine->numElements = newLine.numElements;
+-    tmplLine->elements = newLine.elements;
+-}
+-
+-static void insertElement(struct singleLine * line,
+-			  const char * item, int insertHere,
+-			  struct configFileInfo * cfi)
+-{
+-    struct keywordTypes * kw;
+-    char indent[2] = "";
+-
+-    /* sanity check */
+-    if (insertHere > line->numElements) {
+-	dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
+-		  insertHere, line->numElements);
+-	insertHere = line->numElements;
+-    }
+-
+-    line->elements = realloc(line->elements, (line->numElements + 1) * 
+-			     sizeof(*line->elements));
+-    memmove(&line->elements[insertHere+1], 
+-	    &line->elements[insertHere], 
+-	    (line->numElements - insertHere) * 
+-	    sizeof(*line->elements));
+-    line->elements[insertHere].item = strdup(item);
+-
+-    kw = getKeywordByType(line->type, cfi);
+-
+-    if (line->numElements == 0) {
+-	indent[0] = '\0';
+-    } else if (insertHere == 0) {
+-	indent[0] = kw->nextChar;
+-    } else if (kw->separatorChar != '\0') {
+-	indent[0] = kw->separatorChar;
+-    } else {
+-	indent[0] = ' ';
+-    }
+-
+-    if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
+-	/* move the end-of-line forward */
+-	line->elements[insertHere].indent = 
+-	    line->elements[insertHere-1].indent;
+-	line->elements[insertHere-1].indent = strdup(indent);
+-    } else {
+-	line->elements[insertHere].indent = strdup(indent);
+-    }
+-
+-    line->numElements++;
+-
+-    dbgPrintf("insertElement(%s, '%s%s', %d)\n",
+-	      line->elements[0].item,
+-	      line->elements[insertHere].item,
+-	      line->elements[insertHere].indent,
+-	      insertHere);
+-}
+-
+-static void removeElement(struct singleLine * line, int removeHere) {
+-    int i;
+-
+-    /* sanity check */
+-    if (removeHere >= line->numElements) return;
+-
+-    dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item, 
+-	      removeHere, line->elements[removeHere].item);
+-
+-    free(line->elements[removeHere].item);
+-
+-    if (removeHere > 1) {
+-	/* previous argument gets this argument's post-indentation */
+-	free(line->elements[removeHere-1].indent);
+-	line->elements[removeHere-1].indent =
+-	    line->elements[removeHere].indent;
+-    } else {
+-	free(line->elements[removeHere].indent);
+-    }
+-
+-    /* now collapse the array, but don't bother to realloc smaller */
+-    for (i = removeHere; i < line->numElements - 1; i++)
+-	line->elements[i] = line->elements[i + 1];
+-
+-    line->numElements--;
+-}
+-
+-int argMatch(const char * one, const char * two) {
+-    char * first, * second;
+-    char * chptr;
+-
+-    first = strcpy(alloca(strlen(one) + 1), one);
+-    second = strcpy(alloca(strlen(two) + 1), two);
+-
+-    chptr = strchr(first, '=');
+-    if (chptr) *chptr = '\0';
+-
+-    chptr = strchr(second, '=');
+-    if (chptr) *chptr = '\0';
+-
+-    return strcmp(first, second);
+-}
+-
+-int updateActualImage(struct grubConfig * cfg, const char * image,
+-                      const char * prefix, const char * addArgs,
+-                      const char * removeArgs, int multibootArgs) {
+-    struct singleEntry * entry;
+-    struct singleLine * line, * rootLine;
+-    int index = 0;
+-    int i, k;
+-    const char ** newArgs, ** oldArgs;
+-    const char ** arg;
+-    int useKernelArgs, useRoot;
+-    int firstElement;
+-    int *usedElements;
+-    int doreplace;
+-
+-    if (!image) return 0;
+-
+-    if (!addArgs) {
+-	newArgs = malloc(sizeof(*newArgs));
+-	*newArgs = NULL;
+-    } else {
+-	if (poptParseArgvString(addArgs, NULL, &newArgs)) {
+-	    fprintf(stderr, 
+-		    _("grubby: error separating arguments '%s'\n"), addArgs);
+-	    return 1;
+-	}
+-    }
+-
+-    if (!removeArgs) {
+-	oldArgs = malloc(sizeof(*oldArgs));
+-	*oldArgs = NULL;
+-    } else {
+-	if (poptParseArgvString(removeArgs, NULL, &oldArgs)) {
+-	    fprintf(stderr, 
+-		    _("grubby: error separating arguments '%s'\n"), removeArgs);
+-            free(newArgs);
+-	    return 1;
+-	}
+-    }
+-
+-
+-    useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
+-		     && (!multibootArgs || cfg->cfi->mbConcatArgs));
+-
+-    useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
+-	       && !multibootArgs);
+-
+-    for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
+-
+-	if (multibootArgs && !entry->multiboot)
+-	    continue;
+-
+-	/* Determine where to put the args.  If this config supports
+-	 * LT_KERNELARGS, use that.  Otherwise use
+-	 * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
+-	 */
+-	if (useKernelArgs) {
+-	    line = getLineByType(LT_KERNELARGS, entry->lines);
+-	    if (!line) {
+-		/* no LT_KERNELARGS, need to add it */
+-		line = addLine(entry, cfg->cfi, LT_KERNELARGS, 
+-			       cfg->secondaryIndent, NULL);
+-	    }
+-	    firstElement = 1;
+-
+-	} else if (multibootArgs) {
+-	    line = getLineByType(LT_HYPER, entry->lines);
+-	    if (!line) {
+-		/* a multiboot entry without LT_HYPER? */
+-		continue;
+-	    }
+-	    firstElement = 2;
+-
+-	} else {
+-	    line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
+-	    if (!line) {
+-		/* no LT_KERNEL or LT_MBMODULE in this entry? */
+-		continue;
+-	    }
+-	    firstElement = 2;
+-	}
+-
+-	/* handle the elilo case which does:
+-	 *   append="hypervisor args -- kernel args"
+-	 */
+-	if (entry->multiboot && cfg->cfi->mbConcatArgs) {
+-	    /* this is a multiboot entry, make sure there's
+-	     * -- on the args line
+-	     */
+-	    for (i = firstElement; i < line->numElements; i++) {
+-		if (!strcmp(line->elements[i].item, "--"))
+-		    break;
+-	    }
+-	    if (i == line->numElements) {
+-		/* assume all existing args are kernel args,
+-		 * prepend -- to make it official
++		/* override the inherited value with our own.
++		 * This is a little weak because it only applies to elements[1]
+ 		 */
+-		insertElement(line, "--", firstElement, cfg->cfi);
+-		i = firstElement;
+-	    }
+-	    if (!multibootArgs) {
+-		/* kernel args start after the -- */
+-		firstElement = i + 1;
+-	    }
+-	} else if (cfg->cfi->mbConcatArgs) {
+-	    /* this is a non-multiboot entry, remove hyper args */
+-	    for (i = firstElement; i < line->numElements; i++) {
+-		if (!strcmp(line->elements[i].item, "--"))
+-		    break;
+-	    }
+-	    if (i < line->numElements) {
+-		/* remove args up to -- */
+-		while (strcmp(line->elements[firstElement].item, "--"))
+-		    removeElement(line, firstElement);
+-		/* remove -- */
+-		removeElement(line, firstElement);
+-	    }
++		if (newLine->numElements > 1)
++			removeElement(newLine, 1);
++		insertElement(newLine, val, 1, cfi);
++
++		/* but try to keep the rootspec from the template... sigh */
++		if (tmplLine->
++		    type & (LT_HYPER | LT_KERNEL | LT_MBMODULE | LT_INITRD |
++			    LT_KERNEL_EFI | LT_INITRD_EFI | LT_KERNEL_16 |
++			    LT_INITRD_16)) {
++			char *rootspec =
++			    getRootSpecifier(tmplLine->elements[1].item);
++			if (rootspec != NULL) {
++				free(newLine->elements[1].item);
++				newLine->elements[1].item =
++				    sdupprintf("%s%s", rootspec, val);
++			}
++		}
++	}
++
++	dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
++		  newLine->elements[0].item : "");
++
++	if (!entry->lines) {
++		/* first one on the list */
++		entry->lines = newLine;
++	} else if (prevLine) {
++		/* add after prevLine */
++		newLine->next = prevLine->next;
++		prevLine->next = newLine;
+ 	}
+ 
+-        usedElements = calloc(line->numElements, sizeof(*usedElements));
++	return newLine;
++}
+ 
+-	for (k = 0, arg = newArgs; *arg; arg++, k++) {
++/* val may be NULL */
++struct singleLine *addLine(struct singleEntry *entry,
++			   struct configFileInfo *cfi,
++			   enum lineType_e type, char *defaultIndent,
++			   const char *val)
++{
++	struct singleLine *line, *prev;
++	struct keywordTypes *kw;
++	struct singleLine tmpl;
+ 
+-	    doreplace = 1;
+-	    for (i = firstElement; i < line->numElements; i++) {
+-		if (multibootArgs && cfg->cfi->mbConcatArgs && 
+-		    !strcmp(line->elements[i].item, "--")) 
+-		{
+-		    /* reached the end of hyper args, insert here */
+-		    doreplace = 0;
+-		    break;  
++	/* NB: This function shouldn't allocate items on the heap, rather on
++	 * the stack since it calls addLineTmpl which will make copies.
++	 */
++	if (type == LT_TITLE && cfi->titleBracketed) {
++		/* we're doing a bracketed title (zipl) */
++		tmpl.type = type;
++		tmpl.numElements = 1;
++		tmpl.elements = alloca(sizeof(*tmpl.elements));
++		tmpl.elements[0].item = alloca(strlen(val) + 3);
++		sprintf(tmpl.elements[0].item, "[%s]", val);
++		tmpl.elements[0].indent = "";
++		val = NULL;
++	} else if (type == LT_MENUENTRY) {
++		char *lineend = "--class gnu-linux --class gnu --class os {";
++		if (!val) {
++			fprintf(stderr,
++				"Line type LT_MENUENTRY requires a value\n");
++			abort();
++		}
++		kw = getKeywordByType(type, cfi);
++		if (!kw) {
++			fprintf(stderr,
++				"Looking up keyword for unknown type %d\n",
++				type);
++			abort();
++		}
++		tmpl.indent = "";
++		tmpl.type = type;
++		tmpl.numElements = 3;
++		tmpl.elements =
++		    alloca(sizeof(*tmpl.elements) * tmpl.numElements);
++		tmpl.elements[0].item = kw->key;
++		tmpl.elements[0].indent = alloca(2);
++		sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
++		tmpl.elements[1].item = (char *)val;
++		tmpl.elements[1].indent = alloca(2);
++		sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
++		tmpl.elements[2].item = alloca(strlen(lineend) + 1);
++		strcpy(tmpl.elements[2].item, lineend);
++		tmpl.elements[2].indent = "";
++	} else {
++		kw = getKeywordByType(type, cfi);
++		if (!kw) {
++			fprintf(stderr,
++				"Looking up keyword for unknown type %d\n",
++				type);
++			abort();
++		}
++		tmpl.type = type;
++		tmpl.numElements = val ? 2 : 1;
++		tmpl.elements =
++		    alloca(sizeof(*tmpl.elements) * tmpl.numElements);
++		tmpl.elements[0].item = kw->key;
++		tmpl.elements[0].indent = alloca(2);
++		sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
++		if (val) {
++			tmpl.elements[1].item = (char *)val;
++			tmpl.elements[1].indent = "";
+ 		}
+-                if (usedElements[i])
+-                    continue;
+-		if (!argMatch(line->elements[i].item, *arg)) {
+-                    usedElements[i]=1;
+-		    break;
+-                }
+-            }
+-
+-	    if (i < line->numElements && doreplace) {
+-		/* direct replacement */
++	}
++
++	/* The last non-empty line gives us the indention to us and the line
++	 * to insert after. Note that comments are considered empty lines,
++	 * which may not be ideal? If there are no lines or we are looking at
++	 * the first line, we use defaultIndent (the first line is normally
++	 * indented differently from the rest) */
++	for (line = entry->lines, prev = NULL; line; line = line->next) {
++		if (line->numElements)
++			prev = line;
++		/* fall back on the last line if prev isn't otherwise set */
++		if (!line->next && !prev)
++			prev = line;
++	}
++
++	struct singleLine *menuEntry;
++	menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
++	if (tmpl.type == LT_ENTRY_END) {
++		if (menuEntry)
++			tmpl.indent = menuEntry->indent;
++		else
++			tmpl.indent = defaultIndent ? : "";
++	} else if (tmpl.type != LT_MENUENTRY) {
++		if (menuEntry)
++			tmpl.indent = "\t";
++		else if (prev == entry->lines)
++			tmpl.indent = defaultIndent ? : "";
++		else
++			tmpl.indent = prev->indent;
++	}
++
++	return addLineTmpl(entry, &tmpl, prev, val, cfi);
++}
++
++void removeLine(struct singleEntry *entry, struct singleLine *line)
++{
++	struct singleLine *prev;
++	int i;
++
++	for (i = 0; i < line->numElements; i++) {
+ 		free(line->elements[i].item);
+-		line->elements[i].item = strdup(*arg);
+-
+-	    } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
+-		/* root= replacement */
+-		rootLine = getLineByType(LT_ROOT, entry->lines);
+-		if (rootLine) {
+-		    free(rootLine->elements[1].item);
+-		    rootLine->elements[1].item = strdup(*arg + 5);
++		free(line->elements[i].indent);
++	}
++	free(line->elements);
++	free(line->indent);
++
++	if (line == entry->lines) {
++		entry->lines = line->next;
++	} else {
++		prev = entry->lines;
++		while (prev->next != line)
++			prev = prev->next;
++		prev->next = line->next;
++	}
++
++	free(line);
++}
++
++static void requote(struct singleLine *tmplLine, struct configFileInfo *cfi)
++{
++	struct singleLine newLine = {
++		.indent = tmplLine->indent,
++		.type = tmplLine->type,
++		.next = tmplLine->next,
++	};
++	int firstQuotedItem = -1;
++	int quoteLen = 0;
++	int j;
++	int element = 0;
++	char *c;
++
++	c = malloc(strlen(tmplLine->elements[0].item) + 1);
++	strcpy(c, tmplLine->elements[0].item);
++	insertElement(&newLine, c, element++, cfi);
++	free(c);
++	c = NULL;
++
++	for (j = 1; j < tmplLine->numElements; j++) {
++		if (firstQuotedItem == -1) {
++			quoteLen += strlen(tmplLine->elements[j].item);
++
++			if (isquote(tmplLine->elements[j].item[0])) {
++				firstQuotedItem = j;
++				quoteLen +=
++				    strlen(tmplLine->elements[j].indent);
++			} else {
++				c = malloc(quoteLen + 1);
++				strcpy(c, tmplLine->elements[j].item);
++				insertElement(&newLine, c, element++, cfi);
++				free(c);
++				quoteLen = 0;
++			}
+ 		} else {
+-		    rootLine = addLine(entry, cfg->cfi, LT_ROOT, 
+-				       cfg->secondaryIndent, *arg + 5);
+-		}
+-	    }
+-
+-	    else {
+-		/* insert/append */
+-		insertElement(line, *arg, i, cfg->cfi);
+-		usedElements = realloc(usedElements, line->numElements *
+-				       sizeof(*usedElements));
+-		memmove(&usedElements[i + 1], &usedElements[i],
+-			line->numElements - i - 1);
+-		usedElements[i] = 1;
+-
+-		/* if we updated a root= here even though there is a
+-		   LT_ROOT available we need to remove the LT_ROOT entry
+-		   (this will happen if we switch from a device to a label) */
+-		if (useRoot && !strncmp(*arg, "root=", 5)) {
+-		    rootLine = getLineByType(LT_ROOT, entry->lines);
+-		    if (rootLine)
+-			removeLine(entry, rootLine);
+-		}
+-	    }
+-	}
+-
+-        free(usedElements);
+-
+-	for (arg = oldArgs; *arg; arg++) {
+-	    for (i = firstElement; i < line->numElements; i++) {
+-		if (multibootArgs && cfg->cfi->mbConcatArgs && 
+-		    !strcmp(line->elements[i].item, "--")) 
+-		    /* reached the end of hyper args, stop here */
+-		    break;
+-		if (!argMatch(line->elements[i].item, *arg)) {
+-		    removeElement(line, i);
+-		    break;
+-		}
+-	    }
+-	    /* handle removing LT_ROOT line too */
+-	    if (useRoot && !strncmp(*arg, "root=", 5)) {
+-		rootLine = getLineByType(LT_ROOT, entry->lines);
+-		if (rootLine)
+-		    removeLine(entry, rootLine);
+-	    }
+-	}
+-
+-	if (line->numElements == 1) {
+-	    /* don't need the line at all (note it has to be a
+-	       LT_KERNELARGS for this to happen */
+-	    removeLine(entry, line);
+-	}
+-    }
+-
+-    free(newArgs);
+-    free(oldArgs);
+-
+-    return 0;
++			int itemlen = strlen(tmplLine->elements[j].item);
++			quoteLen += itemlen;
++			quoteLen += strlen(tmplLine->elements[j].indent);
++
++			if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
++				c = malloc(quoteLen + 1);
++				c[0] = '\0';
++				for (int i = firstQuotedItem; i < j + 1; i++) {
++					strcat(c, tmplLine->elements[i].item);
++					strcat(c, tmplLine->elements[i].indent);
++				}
++				insertElement(&newLine, c, element++, cfi);
++				free(c);
++
++				firstQuotedItem = -1;
++				quoteLen = 0;
++			}
++		}
++	}
++	while (tmplLine->numElements)
++		removeElement(tmplLine, 0);
++	if (tmplLine->elements)
++		free(tmplLine->elements);
++
++	tmplLine->numElements = newLine.numElements;
++	tmplLine->elements = newLine.elements;
+ }
+ 
+-int updateImage(struct grubConfig * cfg, const char * image,
+-                const char * prefix, const char * addArgs,
+-                const char * removeArgs, 
+-                const char * addMBArgs, const char * removeMBArgs) {
+-    int rc = 0;
++static void insertElement(struct singleLine *line,
++			  const char *item, int insertHere,
++			  struct configFileInfo *cfi)
++{
++	struct keywordTypes *kw;
++	char indent[2] = "";
++
++	/* sanity check */
++	if (insertHere > line->numElements) {
++		dbgPrintf
++		    ("insertElement() adjusting insertHere from %d to %d\n",
++		     insertHere, line->numElements);
++		insertHere = line->numElements;
++	}
+ 
+-    if (!image) return rc;
++	line->elements = realloc(line->elements, (line->numElements + 1) *
++				 sizeof(*line->elements));
++	memmove(&line->elements[insertHere + 1],
++		&line->elements[insertHere],
++		(line->numElements - insertHere) * sizeof(*line->elements));
++	line->elements[insertHere].item = strdup(item);
++
++	kw = getKeywordByType(line->type, cfi);
++
++	if (line->numElements == 0) {
++		indent[0] = '\0';
++	} else if (insertHere == 0) {
++		indent[0] = kw->nextChar;
++	} else if (kw->separatorChar != '\0') {
++		indent[0] = kw->separatorChar;
++	} else {
++		indent[0] = ' ';
++	}
+ 
+-    /* update the main args first... */
+-    if (addArgs || removeArgs)
+-        rc = updateActualImage(cfg, image, prefix, addArgs, removeArgs, 0);
+-    if (rc) return rc;
++	if (insertHere > 0 && line->elements[insertHere - 1].indent[0] == '\0') {
++		/* move the end-of-line forward */
++		line->elements[insertHere].indent =
++		    line->elements[insertHere - 1].indent;
++		line->elements[insertHere - 1].indent = strdup(indent);
++	} else {
++		line->elements[insertHere].indent = strdup(indent);
++	}
+ 
+-    /* and now any multiboot args */
+-    if (addMBArgs || removeMBArgs)
+-        rc = updateActualImage(cfg, image, prefix, addMBArgs, removeMBArgs, 1);
+-    return rc;
++	line->numElements++;
++
++	dbgPrintf("insertElement(%s, '%s%s', %d)\n",
++		  line->elements[0].item,
++		  line->elements[insertHere].item,
++		  line->elements[insertHere].indent, insertHere);
+ }
+ 
+-int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
+-		 const char * image, const char * prefix, const char * initrd,
+-		 const char * title) {
+-    struct singleEntry * entry;
+-    struct singleLine * line, * kernelLine, *endLine = NULL;
+-    int index = 0;
+-
+-    if (!image) return 0;
+-
+-    for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
+-        kernelLine = getLineByType(LT_MBMODULE, entry->lines);
+-        if (!kernelLine) continue;
+-
+-	/* if title is supplied, the entry's title must match it. */
+-	if (title) {
+-	    char *linetitle;
+-
+-	    line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
+-	    if (!line)
+-		continue;
+-
+-	    linetitle = extractTitle(cfg, line);
+-	    if (!linetitle)
+-		continue;
+-	    if (strcmp(title, linetitle)) {
+-		free(linetitle);
+-		continue;
+-	    }
+-	    free(linetitle);
+-	}
+-
+-        if (prefix) {
+-            int prefixLen = strlen(prefix);
+-            if (!strncmp(initrd, prefix, prefixLen))
+-                initrd += prefixLen;
+-        }
+-	endLine = getLineByType(LT_ENTRY_END, entry->lines);
+-	if (endLine)
+-	    removeLine(entry, endLine);
+-        line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
+-			kernelLine->indent, initrd);
+-        if (!line)
+-	    return 1;
+-	if (endLine) {
+-	    line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
+-            if (!line)
+-		return 1;
++static void removeElement(struct singleLine *line, int removeHere)
++{
++	int i;
++
++	/* sanity check */
++	if (removeHere >= line->numElements)
++		return;
++
++	dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
++		  removeHere, line->elements[removeHere].item);
++
++	free(line->elements[removeHere].item);
++
++	if (removeHere > 1) {
++		/* previous argument gets this argument's post-indentation */
++		free(line->elements[removeHere - 1].indent);
++		line->elements[removeHere - 1].indent =
++		    line->elements[removeHere].indent;
++	} else {
++		free(line->elements[removeHere].indent);
+ 	}
+ 
+-        break;
+-    }
++	/* now collapse the array, but don't bother to realloc smaller */
++	for (i = removeHere; i < line->numElements - 1; i++)
++		line->elements[i] = line->elements[i + 1];
+ 
+-    return 0;
++	line->numElements--;
+ }
+ 
+-int updateInitrd(struct grubConfig * cfg, const char * image,
+-                 const char * prefix, const char * initrd, const char * title) {
+-    struct singleEntry * entry;
+-    struct singleLine * line, * kernelLine, *endLine = NULL;
+-    int index = 0;
+-
+-    if (!image) return 0;
+-
+-    for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
+-        kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
+-        if (!kernelLine) continue;
+-
+-	/* if title is supplied, the entry's title must match it. */
+-	if (title) {
+-	    char *linetitle;
+-
+-	    line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
+-	    if (!line)
+-		continue;
+-
+-	    linetitle = extractTitle(cfg, line);
+-	    if (!linetitle)
+-		continue;
+-	    if (strcmp(title, linetitle)) {
+-		free(linetitle);
+-		continue;
+-	    }
+-	    free(linetitle);
+-	}
+-
+-        line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
+-        if (line)
+-            removeLine(entry, line);
+-        if (prefix) {
+-            int prefixLen = strlen(prefix);
+-            if (!strncmp(initrd, prefix, prefixLen))
+-                initrd += prefixLen;
+-        }
+-	endLine = getLineByType(LT_ENTRY_END, entry->lines);
+-	if (endLine)
+-	    removeLine(entry, endLine);
+-	enum lineType_e lt;
+-	switch(kernelLine->type) {
+-	    case LT_KERNEL:
+-	        lt = LT_INITRD;
+-		break;
+-	    case LT_KERNEL_EFI:
+-	        lt = LT_INITRD_EFI;
++int argMatch(const char *one, const char *two)
++{
++	char *first, *second;
++	char *chptr;
++
++	first = strcpy(alloca(strlen(one) + 1), one);
++	second = strcpy(alloca(strlen(two) + 1), two);
++
++	chptr = strchr(first, '=');
++	if (chptr)
++		*chptr = '\0';
++
++	chptr = strchr(second, '=');
++	if (chptr)
++		*chptr = '\0';
++
++	return strcmp(first, second);
++}
++
++int updateActualImage(struct grubConfig *cfg, const char *image,
++		      const char *prefix, const char *addArgs,
++		      const char *removeArgs, int multibootArgs)
++{
++	struct singleEntry *entry;
++	struct singleLine *line, *rootLine;
++	int index = 0;
++	int i, k;
++	const char **newArgs, **oldArgs;
++	const char **arg;
++	int useKernelArgs, useRoot;
++	int firstElement;
++	int *usedElements;
++	int doreplace;
++
++	if (!image)
++		return 0;
++
++	if (!addArgs) {
++		newArgs = malloc(sizeof(*newArgs));
++		*newArgs = NULL;
++	} else {
++		if (poptParseArgvString(addArgs, NULL, &newArgs)) {
++			fprintf(stderr,
++				_("grubby: error separating arguments '%s'\n"),
++				addArgs);
++			return 1;
++		}
++	}
++
++	if (!removeArgs) {
++		oldArgs = malloc(sizeof(*oldArgs));
++		*oldArgs = NULL;
++	} else {
++		if (poptParseArgvString(removeArgs, NULL, &oldArgs)) {
++			fprintf(stderr,
++				_("grubby: error separating arguments '%s'\n"),
++				removeArgs);
++			free(newArgs);
++			return 1;
++		}
++	}
++
++	useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
++			 && (!multibootArgs || cfg->cfi->mbConcatArgs));
++
++	useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
++		   && !multibootArgs);
++
++	for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
++
++		if (multibootArgs && !entry->multiboot)
++			continue;
++
++		/* Determine where to put the args.  If this config supports
++		 * LT_KERNELARGS, use that.  Otherwise use
++		 * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
++		 */
++		if (useKernelArgs) {
++			line = getLineByType(LT_KERNELARGS, entry->lines);
++			if (!line) {
++				/* no LT_KERNELARGS, need to add it */
++				line = addLine(entry, cfg->cfi, LT_KERNELARGS,
++					       cfg->secondaryIndent, NULL);
++			}
++			firstElement = 1;
++
++		} else if (multibootArgs) {
++			line = getLineByType(LT_HYPER, entry->lines);
++			if (!line) {
++				/* a multiboot entry without LT_HYPER? */
++				continue;
++			}
++			firstElement = 2;
++
++		} else {
++			line =
++			    getLineByType(LT_KERNEL | LT_MBMODULE |
++					  LT_KERNEL_EFI | LT_KERNEL_16,
++					  entry->lines);
++			if (!line) {
++				/* no LT_KERNEL or LT_MBMODULE in this entry? */
++				continue;
++			}
++			firstElement = 2;
++		}
++
++		/* handle the elilo case which does:
++		 *   append="hypervisor args -- kernel args"
++		 */
++		if (entry->multiboot && cfg->cfi->mbConcatArgs) {
++			/* this is a multiboot entry, make sure there's
++			 * -- on the args line
++			 */
++			for (i = firstElement; i < line->numElements; i++) {
++				if (!strcmp(line->elements[i].item, "--"))
++					break;
++			}
++			if (i == line->numElements) {
++				/* assume all existing args are kernel args,
++				 * prepend -- to make it official
++				 */
++				insertElement(line, "--", firstElement,
++					      cfg->cfi);
++				i = firstElement;
++			}
++			if (!multibootArgs) {
++				/* kernel args start after the -- */
++				firstElement = i + 1;
++			}
++		} else if (cfg->cfi->mbConcatArgs) {
++			/* this is a non-multiboot entry, remove hyper args */
++			for (i = firstElement; i < line->numElements; i++) {
++				if (!strcmp(line->elements[i].item, "--"))
++					break;
++			}
++			if (i < line->numElements) {
++				/* remove args up to -- */
++				while (strcmp
++				       (line->elements[firstElement].item,
++					"--"))
++					removeElement(line, firstElement);
++				/* remove -- */
++				removeElement(line, firstElement);
++			}
++		}
++
++		usedElements = calloc(line->numElements, sizeof(*usedElements));
++
++		for (k = 0, arg = newArgs; *arg; arg++, k++) {
++
++			doreplace = 1;
++			for (i = firstElement; i < line->numElements; i++) {
++				if (multibootArgs && cfg->cfi->mbConcatArgs &&
++				    !strcmp(line->elements[i].item, "--")) {
++					/* reached the end of hyper args, insert here */
++					doreplace = 0;
++					break;
++				}
++				if (usedElements[i])
++					continue;
++				if (!argMatch(line->elements[i].item, *arg)) {
++					usedElements[i] = 1;
++					break;
++				}
++			}
++
++			if (i < line->numElements && doreplace) {
++				/* direct replacement */
++				free(line->elements[i].item);
++				line->elements[i].item = strdup(*arg);
++
++			} else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
++				/* root= replacement */
++				rootLine = getLineByType(LT_ROOT, entry->lines);
++				if (rootLine) {
++					free(rootLine->elements[1].item);
++					rootLine->elements[1].item =
++					    strdup(*arg + 5);
++				} else {
++					rootLine =
++					    addLine(entry, cfg->cfi, LT_ROOT,
++						    cfg->secondaryIndent,
++						    *arg + 5);
++				}
++			}
++
++			else {
++				/* insert/append */
++				insertElement(line, *arg, i, cfg->cfi);
++				usedElements =
++				    realloc(usedElements,
++					    line->numElements *
++					    sizeof(*usedElements));
++				memmove(&usedElements[i + 1], &usedElements[i],
++					line->numElements - i - 1);
++				usedElements[i] = 1;
++
++				/* if we updated a root= here even though
++				 * there is a LT_ROOT available we need to
++				 * remove the LT_ROOT entry (this will happen
++				 * if we switch from a device to a label) */
++				if (useRoot && !strncmp(*arg, "root=", 5)) {
++					rootLine =
++					    getLineByType(LT_ROOT,
++							  entry->lines);
++					if (rootLine)
++						removeLine(entry, rootLine);
++				}
++			}
++		}
++
++		free(usedElements);
++
++		for (arg = oldArgs; *arg; arg++) {
++			for (i = firstElement; i < line->numElements; i++) {
++				if (multibootArgs && cfg->cfi->mbConcatArgs &&
++				    !strcmp(line->elements[i].item, "--"))
++					/* reached the end of hyper args, stop here */
++					break;
++				if (!argMatch(line->elements[i].item, *arg)) {
++					removeElement(line, i);
++					break;
++				}
++			}
++			/* handle removing LT_ROOT line too */
++			if (useRoot && !strncmp(*arg, "root=", 5)) {
++				rootLine = getLineByType(LT_ROOT, entry->lines);
++				if (rootLine)
++					removeLine(entry, rootLine);
++			}
++		}
++
++		if (line->numElements == 1) {
++			/* don't need the line at all (note it has to be a
++			   LT_KERNELARGS for this to happen */
++			removeLine(entry, line);
++		}
++	}
++
++	free(newArgs);
++	free(oldArgs);
++
++	return 0;
++}
++
++int updateImage(struct grubConfig *cfg, const char *image,
++		const char *prefix, const char *addArgs,
++		const char *removeArgs,
++		const char *addMBArgs, const char *removeMBArgs)
++{
++	int rc = 0;
++
++	if (!image)
++		return rc;
++
++	/* update the main args first... */
++	if (addArgs || removeArgs)
++		rc = updateActualImage(cfg, image, prefix, addArgs, removeArgs,
++				       0);
++	if (rc)
++		return rc;
++
++	/* and now any multiboot args */
++	if (addMBArgs || removeMBArgs)
++		rc = updateActualImage(cfg, image, prefix, addMBArgs,
++				       removeMBArgs, 1);
++	return rc;
++}
++
++int addMBInitrd(struct grubConfig *cfg, const char *newMBKernel,
++		const char *image, const char *prefix, const char *initrd,
++		const char *title)
++{
++	struct singleEntry *entry;
++	struct singleLine *line, *kernelLine, *endLine = NULL;
++	int index = 0;
++
++	if (!image)
++		return 0;
++
++	for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
++		kernelLine = getLineByType(LT_MBMODULE, entry->lines);
++		if (!kernelLine)
++			continue;
++
++		/* if title is supplied, the entry's title must match it. */
++		if (title) {
++			char *linetitle;
++
++			line =
++			    getLineByType(LT_TITLE | LT_MENUENTRY,
++					  entry->lines);
++			if (!line)
++				continue;
++
++			linetitle = extractTitle(cfg, line);
++			if (!linetitle)
++				continue;
++			if (strcmp(title, linetitle)) {
++				free(linetitle);
++				continue;
++			}
++			free(linetitle);
++		}
++
++		if (prefix) {
++			int prefixLen = strlen(prefix);
++			if (!strncmp(initrd, prefix, prefixLen))
++				initrd += prefixLen;
++		}
++		endLine = getLineByType(LT_ENTRY_END, entry->lines);
++		if (endLine)
++			removeLine(entry, endLine);
++		line =
++		    addLine(entry, cfg->cfi,
++			    preferredLineType(LT_MBMODULE, cfg->cfi),
++			    kernelLine->indent, initrd);
++		if (!line)
++			return 1;
++		if (endLine) {
++			line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
++			if (!line)
++				return 1;
++		}
++
+ 		break;
+-	    case LT_KERNEL_16:
+-	        lt = LT_INITRD_16;
++	}
++
++	return 0;
++}
++
++int updateInitrd(struct grubConfig *cfg, const char *image,
++		 const char *prefix, const char *initrd, const char *title)
++{
++	struct singleEntry *entry;
++	struct singleLine *line, *kernelLine, *endLine = NULL;
++	int index = 0;
++
++	if (!image)
++		return 0;
++
++	for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
++		kernelLine =
++		    getLineByType(LT_KERNEL | LT_KERNEL_EFI | LT_KERNEL_16,
++				  entry->lines);
++		if (!kernelLine)
++			continue;
++
++		/* if title is supplied, the entry's title must match it. */
++		if (title) {
++			char *linetitle;
++
++			line =
++			    getLineByType(LT_TITLE | LT_MENUENTRY,
++					  entry->lines);
++			if (!line)
++				continue;
++
++			linetitle = extractTitle(cfg, line);
++			if (!linetitle)
++				continue;
++			if (strcmp(title, linetitle)) {
++				free(linetitle);
++				continue;
++			}
++			free(linetitle);
++		}
++
++		line =
++		    getLineByType(LT_INITRD | LT_INITRD_EFI | LT_INITRD_16,
++				  entry->lines);
++		if (line)
++			removeLine(entry, line);
++		if (prefix) {
++			int prefixLen = strlen(prefix);
++			if (!strncmp(initrd, prefix, prefixLen))
++				initrd += prefixLen;
++		}
++		endLine = getLineByType(LT_ENTRY_END, entry->lines);
++		if (endLine)
++			removeLine(entry, endLine);
++		enum lineType_e lt;
++		switch (kernelLine->type) {
++		case LT_KERNEL:
++			lt = LT_INITRD;
++			break;
++		case LT_KERNEL_EFI:
++			lt = LT_INITRD_EFI;
++			break;
++		case LT_KERNEL_16:
++			lt = LT_INITRD_16;
++			break;
++		default:
++			lt = preferredLineType(LT_INITRD, cfg->cfi);
++		}
++		line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
++		if (!line)
++			return 1;
++		if (endLine) {
++			line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
++			if (!line)
++				return 1;
++		}
++
+ 		break;
+-	    default:
+-	        lt = preferredLineType(LT_INITRD, cfg->cfi);
+-	}
+-        line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
+-        if (!line)
+-	    return 1;
+-	if (endLine) {
+-	    line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
+-            if (!line)
++	}
++
++	return 0;
++}
++
++int checkDeviceBootloader(const char *device, const unsigned char *boot)
++{
++	int fd;
++	unsigned char bootSect[512];
++	int offset;
++
++	fd = open(device, O_RDONLY);
++	if (fd < 0) {
++		fprintf(stderr, _("grubby: unable to open %s: %s\n"),
++			device, strerror(errno));
+ 		return 1;
+ 	}
+ 
+-        break;
+-    }
++	if (read(fd, bootSect, 512) != 512) {
++		fprintf(stderr, _("grubby: unable to read %s: %s\n"),
++			device, strerror(errno));
++		return 1;
++	}
++	close(fd);
++
++	/* first three bytes should match, a jmp short should be in there */
++	if (memcmp(boot, bootSect, 3))
++		return 0;
++
++	if (boot[1] == JMP_SHORT_OPCODE) {
++		offset = boot[2] + 2;
++	} else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
++		offset = (boot[3] << 8) + boot[2] + 2;
++	} else if (boot[0] == JMP_SHORT_OPCODE) {
++		offset = boot[1] + 2;
++		/*
++		 * it looks like grub, when copying stage1 into the mbr,
++		 * patches stage1 right after the JMP location, replacing
++		 * other instructions such as JMPs for NOOPs. So, relax the
++		 * check a little bit by skipping those different bytes.
++		 */
++		if ((bootSect[offset + 1] == NOOP_OPCODE)
++		    && (bootSect[offset + 2] == NOOP_OPCODE)) {
++			offset = offset + 3;
++		}
++	} else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
++		offset = (boot[2] << 8) + boot[1] + 2;
++	} else {
++		return 0;
++	}
++
++	if (memcmp(boot + offset, bootSect + offset, CODE_SEG_SIZE))
++		return 0;
+ 
+-    return 0;
++	return 2;
+ }
+ 
+-int checkDeviceBootloader(const char * device, const unsigned char * boot) {
+-    int fd;
+-    unsigned char bootSect[512];
+-    int offset;
++int checkLiloOnRaid(char *mdDev, const unsigned char *boot)
++{
++	int fd;
++	char buf[65536];
++	char *end;
++	char *chptr;
++	char *chptr2;
++	int rc;
++
++	/* it's on raid; we need to parse /proc/mdstat and check all of the
++	 *raw* devices listed in there */
++
++	if (!strncmp(mdDev, "/dev/", 5))
++		mdDev += 5;
++
++	if ((fd = open("/proc/mdstat", O_RDONLY)) < 0) {
++		fprintf(stderr, _("grubby: failed to open /proc/mdstat: %s\n"),
++			strerror(errno));
++		return 2;
++	}
+ 
+-    fd = open(device, O_RDONLY);
+-    if (fd < 0) {
+-	fprintf(stderr, _("grubby: unable to open %s: %s\n"),
+-		device, strerror(errno));
+-	return 1;
+-    }
++	rc = read(fd, buf, sizeof(buf) - 1);
++	if (rc < 0 || rc == (sizeof(buf) - 1)) {
++		fprintf(stderr, _("grubby: failed to read /proc/mdstat: %s\n"),
++			strerror(errno));
++		close(fd);
++		return 2;
++	}
++	close(fd);
++	buf[rc] = '\0';
++
++	chptr = buf;
++	while (*chptr) {
++		end = strchr(chptr, '\n');
++		if (!end)
++			break;
++		*end = '\0';
++
++		if (!strncmp(chptr, mdDev, strlen(mdDev)) &&
++		    chptr[strlen(mdDev)] == ' ') {
++
++			/* found the device */
++			while (*chptr && *chptr != ':')
++				chptr++;
++			chptr++;
++			while (*chptr && isspace(*chptr))
++				chptr++;
++
++			/* skip the "active" bit */
++			while (*chptr && !isspace(*chptr))
++				chptr++;
++			while (*chptr && isspace(*chptr))
++				chptr++;
++
++			/* skip the raid level */
++			while (*chptr && !isspace(*chptr))
++				chptr++;
++			while (*chptr && isspace(*chptr))
++				chptr++;
++
++			/* everything else is partition stuff */
++			while (*chptr) {
++				chptr2 = chptr;
++				while (*chptr2 && *chptr2 != '[')
++					chptr2++;
++				if (!*chptr2)
++					break;
++
++				/* yank off the numbers at the end */
++				chptr2--;
++				while (isdigit(*chptr2) && chptr2 > chptr)
++					chptr2--;
++				chptr2++;
++				*chptr2 = '\0';
++
++				/* Better, now we need the /dev/ back. We're
++				 * done with everything before this point, so
++				 * we can just put the /dev/ part there.
++				 * There will always be room. */
++				memcpy(chptr - 5, "/dev/", 5);
++				rc = checkDeviceBootloader(chptr - 5, boot);
++				if (rc != 2) {
++					return rc;
++				}
++
++				chptr = chptr2 + 1;
++				/* skip the [11] bit */
++				while (*chptr && !isspace(*chptr))
++					chptr++;
++				/* and move to the next one */
++				while (*chptr && isspace(*chptr))
++					chptr++;
++			}
++
++			/*  we're good to go */
++			return 2;
++		}
+ 
+-    if (read(fd, bootSect, 512) != 512) {
+-	fprintf(stderr, _("grubby: unable to read %s: %s\n"),
+-		device, strerror(errno));
+-	return 1;
+-    }
+-    close(fd);
++		chptr = end + 1;
++	}
+ 
+-    /* first three bytes should match, a jmp short should be in there */
+-    if (memcmp(boot, bootSect, 3))
++	fprintf(stderr,
++		_("grubby: raid device /dev/%s not found in /proc/mdstat\n"),
++		mdDev);
+ 	return 0;
++}
++
++int checkForLilo(struct grubConfig *config)
++{
++	int fd;
++	unsigned char boot[512];
++	struct singleLine *line;
++
++	for (line = config->theLines; line; line = line->next)
++		if (line->type == LT_BOOT)
++			break;
++
++	if (!line) {
++		fprintf(stderr,
++			_
++			("grubby: no boot line found in lilo configuration\n"));
++		return 1;
++	}
++
++	if (line->numElements != 2)
++		return 1;
++
++	fd = open("/boot/boot.b", O_RDONLY);
++	if (fd < 0) {
++		fprintf(stderr, _("grubby: unable to open %s: %s\n"),
++			"/boot/boot.b", strerror(errno));
++		return 1;
++	}
++
++	if (read(fd, boot, 512) != 512) {
++		fprintf(stderr, _("grubby: unable to read %s: %s\n"),
++			"/boot/boot.b", strerror(errno));
++		return 1;
++	}
++	close(fd);
++
++	if (!strncmp("/dev/md", line->elements[1].item, 7))
++		return checkLiloOnRaid(line->elements[1].item, boot);
++
++	return checkDeviceBootloader(line->elements[1].item, boot);
++}
++
++int checkForGrub2(struct grubConfig *config)
++{
++	if (!access("/etc/grub.d/", R_OK))
++		return 2;
++
++	return 1;
++}
++
++int checkForGrub(struct grubConfig *config)
++{
++	int fd;
++	unsigned char bootSect[512];
++	char *boot;
++	int onSuse = isSuseSystem();
++
++	if (onSuse) {
++		if (parseSuseGrubConf(NULL, &boot))
++			return 0;
++	} else {
++		if (parseSysconfigGrub(NULL, &boot))
++			return 0;
++	}
++
++	/* assume grub is not installed -- not an error condition */
++	if (!boot)
++		return 0;
++
++	fd = open("/boot/grub/stage1", O_RDONLY);
++	if (fd < 0)
++		/* this doesn't exist if grub hasn't been installed */
++		return 0;
++
++	if (read(fd, bootSect, 512) != 512) {
++		fprintf(stderr, _("grubby: unable to read %s: %s\n"),
++			"/boot/grub/stage1", strerror(errno));
++		close(fd);
++		return 1;
++	}
++	close(fd);
+ 
+-    if (boot[1] == JMP_SHORT_OPCODE) {
+-	offset = boot[2] + 2;
+-    } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
+-	offset = (boot[3] << 8) + boot[2] + 2;
+-    } else if (boot[0] == JMP_SHORT_OPCODE) {
+-      offset = boot[1] + 2;
+-        /*
+-	 * it looks like grub, when copying stage1 into the mbr, patches stage1
+-	 * right after the JMP location, replacing other instructions such as
+-	 * JMPs for NOOPs. So, relax the check a little bit by skipping those
+-	 * different bytes.
++	/* The more elaborate checks do not work on SuSE. The checks done
++	 * seem to be reasonble (at least for now), so just return success
+ 	 */
+-      if ((bootSect[offset + 1] == NOOP_OPCODE)
+-	  && (bootSect[offset + 2] == NOOP_OPCODE)) {
+-	offset = offset + 3;
+-      }
+-    } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
+-	offset = (boot[2] << 8) + boot[1] + 2;
+-    } else {
+-	return 0;
+-    }
++	if (onSuse)
++		return 2;
+ 
+-    if (memcmp(boot + offset, bootSect + offset, CODE_SEG_SIZE))
+-	return 0;
+-
+-    return 2;
+-}
+-
+-int checkLiloOnRaid(char * mdDev, const unsigned char * boot) {
+-    int fd;
+-    char buf[65536];
+-    char * end;
+-    char * chptr;
+-    char * chptr2;
+-    int rc;
+-
+-    /* it's on raid; we need to parse /proc/mdstat and check all of the
+-       *raw* devices listed in there */
+-
+-    if (!strncmp(mdDev, "/dev/", 5))
+-	mdDev += 5;
+-
+-    if ((fd = open("/proc/mdstat", O_RDONLY)) < 0) {
+-	fprintf(stderr, _("grubby: failed to open /proc/mdstat: %s\n"),
+-		strerror(errno));
+-	return 2;
+-    }
+-
+-    rc = read(fd, buf, sizeof(buf) - 1);
+-    if (rc < 0 || rc == (sizeof(buf) - 1)) {
+-	fprintf(stderr, _("grubby: failed to read /proc/mdstat: %s\n"),
+-		strerror(errno));
+-	close(fd);
+-	return 2;
+-    }
+-    close(fd);
+-    buf[rc] = '\0';
+-
+-    chptr = buf;
+-    while (*chptr) {
+-	end = strchr(chptr, '\n');
+-	if (!end) break;
+-	*end = '\0';
+-
+-	if (!strncmp(chptr, mdDev, strlen(mdDev)) && 
+-	    chptr[strlen(mdDev)] == ' ') {
+-
+-	    /* found the device */
+-	    while (*chptr && *chptr != ':') chptr++;
+-	    chptr++;
+-	    while (*chptr && isspace(*chptr)) chptr++;
+-
+-	    /* skip the "active" bit */
+-	    while (*chptr && !isspace(*chptr)) chptr++;
+-	    while (*chptr && isspace(*chptr)) chptr++;
+-
+-	    /* skip the raid level */
+-	    while (*chptr && !isspace(*chptr)) chptr++;
+-	    while (*chptr && isspace(*chptr)) chptr++;
+-
+-	    /* everything else is partition stuff */
+-	    while (*chptr) {
+-		chptr2 = chptr;
+-		while (*chptr2 && *chptr2 != '[') chptr2++;
+-		if (!*chptr2) break;
+-
+-		/* yank off the numbers at the end */
+-		chptr2--;
+-		while (isdigit(*chptr2) && chptr2 > chptr) chptr2--;
+-		chptr2++;
+-		*chptr2 = '\0';
+-
+-		/* Better, now we need the /dev/ back. We're done with
+-		 * everything before this point, so we can just put
+-		 * the /dev/ part there. There will always be room. */
+-		memcpy(chptr - 5, "/dev/", 5);
+-		rc = checkDeviceBootloader(chptr - 5, boot);
+-		if (rc != 2) {
+-		    return rc;
+-		}
+-
+-		chptr = chptr2 + 1;
+-		/* skip the [11] bit */
+-		while (*chptr && !isspace(*chptr)) chptr++;
+-		/* and move to the next one */
+-		while (*chptr && isspace(*chptr)) chptr++;
+-	    }
+-
+-	    /*  we're good to go */
+-	    return 2;
+-	}
+-
+-	chptr = end + 1;
+-    }
+-
+-    fprintf(stderr, 
+-	    _("grubby: raid device /dev/%s not found in /proc/mdstat\n"),
+-	    mdDev);
+-    return 0;
+-}
+-
+-int checkForLilo(struct grubConfig * config) {
+-    int fd;
+-    unsigned char boot[512];
+-    struct singleLine * line;
+-
+-    for (line = config->theLines; line; line = line->next)
+-	if (line->type == LT_BOOT) break;
+-
+-    if (!line) { 
+-	fprintf(stderr, 
+-		_("grubby: no boot line found in lilo configuration\n"));
+-	return 1;
+-    }
+-
+-    if (line->numElements != 2) return 1;
+-
+-    fd = open("/boot/boot.b", O_RDONLY);
+-    if (fd < 0) {
+-	fprintf(stderr, _("grubby: unable to open %s: %s\n"),
+-		"/boot/boot.b", strerror(errno));
+-	return 1;
+-    }
+-
+-    if (read(fd, boot, 512) != 512) {
+-	fprintf(stderr, _("grubby: unable to read %s: %s\n"),
+-		"/boot/boot.b", strerror(errno));
+-	return 1;
+-    }
+-    close(fd);
+-
+-    if (!strncmp("/dev/md", line->elements[1].item, 7))
+-	return checkLiloOnRaid(line->elements[1].item, boot);
+-
+-    return checkDeviceBootloader(line->elements[1].item, boot);
+-}
+-
+-int checkForGrub2(struct grubConfig * config) {
+-    if (!access("/etc/grub.d/", R_OK))
+-	return 2;
+-
+-    return 1;
++	return checkDeviceBootloader(boot, bootSect);
+ }
+ 
+-int checkForGrub(struct grubConfig * config) {
+-    int fd;
+-    unsigned char bootSect[512];
+-    char * boot;
+-    int onSuse = isSuseSystem();
++int checkForExtLinux(struct grubConfig *config)
++{
++	int fd;
++	unsigned char bootSect[512];
++	char *boot;
++	char executable[] = "/boot/extlinux/extlinux";
+ 
++	printf("entered: checkForExtLinux()\n");
+ 
+-    if (onSuse) {
+-	if (parseSuseGrubConf(NULL, &boot))
+-	    return 0;
+-    } else {
+ 	if (parseSysconfigGrub(NULL, &boot))
+-	    return 0;
+-    }
+-
+-    /* assume grub is not installed -- not an error condition */
+-    if (!boot)
+-	return 0;
+-
+-    fd = open("/boot/grub/stage1", O_RDONLY);
+-    if (fd < 0)
+-	/* this doesn't exist if grub hasn't been installed */
+-	return 0;
+-
+-    if (read(fd, bootSect, 512) != 512) {
+-	fprintf(stderr, _("grubby: unable to read %s: %s\n"),
+-		"/boot/grub/stage1", strerror(errno));
+- 	close(fd);
+-	return 1;
+-    }
+-    close(fd);
+-
+-    /* The more elaborate checks do not work on SuSE. The checks done
+-     * seem to be reasonble (at least for now), so just return success
+-     */
+-    if (onSuse)
+-	return 2;
+-
+-    return checkDeviceBootloader(boot, bootSect);
+-}
++		return 0;
+ 
+-int checkForExtLinux(struct grubConfig * config) {
+-    int fd;
+-    unsigned char bootSect[512];
+-    char * boot;
+-    char executable[] = "/boot/extlinux/extlinux";
++	/* assume grub is not installed -- not an error condition */
++	if (!boot)
++		return 0;
+ 
+-    printf("entered: checkForExtLinux()\n");
++	fd = open(executable, O_RDONLY);
++	if (fd < 0)
++		/* this doesn't exist if grub hasn't been installed */
++		return 0;
+ 
+-    if (parseSysconfigGrub(NULL, &boot))
+-	return 0;
++	if (read(fd, bootSect, 512) != 512) {
++		fprintf(stderr, _("grubby: unable to read %s: %s\n"),
++			executable, strerror(errno));
++		return 1;
++	}
++	close(fd);
+ 
+-    /* assume grub is not installed -- not an error condition */
+-    if (!boot)
+-	return 0;
++	return checkDeviceBootloader(boot, bootSect);
++}
+ 
+-    fd = open(executable, O_RDONLY);
+-    if (fd < 0)
+-	/* this doesn't exist if grub hasn't been installed */
+-	return 0;
++int checkForYaboot(struct grubConfig *config)
++{
++	/*
++	 * This is a simplistic check that we consider good enough for own puporses
++	 *
++	 * If we were to properly check if yaboot is *installed* we'd need to:
++	 * 1) get the system boot device (LT_BOOT)
++	 * 2) considering it's a raw filesystem, check if the yaboot binary matches
++	 *    the content on the boot device
++	 * 3) if not, copy the binary to a temporary file and run "addnote" on it
++	 * 4) check again if binary and boot device contents match
++	 */
++	if (!access("/etc/yaboot.conf", R_OK))
++		return 2;
+ 
+-    if (read(fd, bootSect, 512) != 512) {
+-	fprintf(stderr, _("grubby: unable to read %s: %s\n"),
+-		executable, strerror(errno));
+ 	return 1;
+-    }
+-    close(fd);
+-
+-    return checkDeviceBootloader(boot, bootSect);
+ }
+ 
+-int checkForYaboot(struct grubConfig * config) {
+-    /*
+-     * This is a simplistic check that we consider good enough for own puporses
+-     *
+-     * If we were to properly check if yaboot is *installed* we'd need to:
+-     * 1) get the system boot device (LT_BOOT)
+-     * 2) considering it's a raw filesystem, check if the yaboot binary matches
+-     *    the content on the boot device
+-     * 3) if not, copy the binary to a temporary file and run "addnote" on it
+-     * 4) check again if binary and boot device contents match
+-     */
+-    if (!access("/etc/yaboot.conf", R_OK))
+-	return 2;
+-
+-    return 1;
+-}
+-
+-int checkForElilo(struct grubConfig * config) {
+-    if (!access("/etc/elilo.conf", R_OK))
+-	return 2;
++int checkForElilo(struct grubConfig *config)
++{
++	if (!access("/etc/elilo.conf", R_OK))
++		return 2;
+ 
+-    return 1;
++	return 1;
+ }
+ 
+-static char * getRootSpecifier(char * str) {
+-    char * idx, * rootspec = NULL;
++static char *getRootSpecifier(char *str)
++{
++	char *idx, *rootspec = NULL;
+ 
+-    if (*str == '(') {
+-        idx = rootspec = strdup(str);
+-        while(*idx && (*idx != ')') && (!isspace(*idx))) idx++;
+-        *(++idx) = '\0';
+-    }
+-    return rootspec;
++	if (*str == '(') {
++		idx = rootspec = strdup(str);
++		while (*idx && (*idx != ')') && (!isspace(*idx)))
++			idx++;
++		*(++idx) = '\0';
++	}
++	return rootspec;
+ }
+ 
+-static char * getInitrdVal(struct grubConfig * config,
+-			   const char * prefix, struct singleLine *tmplLine,
+-			   const char * newKernelInitrd,
+-			   const char ** extraInitrds, int extraInitrdCount)
++static char *getInitrdVal(struct grubConfig *config,
++			  const char *prefix, struct singleLine *tmplLine,
++			  const char *newKernelInitrd,
++			  const char **extraInitrds, int extraInitrdCount)
+ {
+-    char *initrdVal, *end;
+-    int i;
+-    size_t totalSize;
+-    size_t prefixLen;
+-    char separatorChar;
+-
+-    prefixLen = strlen(prefix);
+-    totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
+-
+-    for (i = 0; i < extraInitrdCount; i++) {
+-	totalSize += sizeof(separatorChar);
+-	totalSize += strlen(extraInitrds[i]) - prefixLen;
+-    }
+-
+-    initrdVal = end = malloc(totalSize);
+-
+-    end = stpcpy (end, newKernelInitrd + prefixLen);
+-
+-    separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
+-    for (i = 0; i < extraInitrdCount; i++) {
+-	const char *extraInitrd;
+-	int j;
+-
+-	extraInitrd = extraInitrds[i] + prefixLen;
+-	/* Don't add entries that are already there */
+-	if (tmplLine != NULL) {
+-	    for (j = 2; j < tmplLine->numElements; j++)
+-		if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
+-		    break;
+-
+-	    if (j != tmplLine->numElements)
+-		continue;
++	char *initrdVal, *end;
++	int i;
++	size_t totalSize;
++	size_t prefixLen;
++	char separatorChar;
++
++	prefixLen = strlen(prefix);
++	totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */ ;
++
++	for (i = 0; i < extraInitrdCount; i++) {
++		totalSize += sizeof(separatorChar);
++		totalSize += strlen(extraInitrds[i]) - prefixLen;
+ 	}
+ 
+-	*end++ = separatorChar;
+-	end = stpcpy(end, extraInitrd);
+-    }
++	initrdVal = end = malloc(totalSize);
++
++	end = stpcpy(end, newKernelInitrd + prefixLen);
++
++	separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
++	for (i = 0; i < extraInitrdCount; i++) {
++		const char *extraInitrd;
++		int j;
+ 
+-    return initrdVal;
++		extraInitrd = extraInitrds[i] + prefixLen;
++		/* Don't add entries that are already there */
++		if (tmplLine != NULL) {
++			for (j = 2; j < tmplLine->numElements; j++)
++				if (strcmp
++				    (extraInitrd,
++				     tmplLine->elements[j].item) == 0)
++					break;
++
++			if (j != tmplLine->numElements)
++				continue;
++		}
++
++		*end++ = separatorChar;
++		end = stpcpy(end, extraInitrd);
++	}
++
++	return initrdVal;
+ }
+ 
+-int addNewKernel(struct grubConfig * config, struct singleEntry * template, 
+-	         const char * prefix,
+-		 const char * newKernelPath, const char * newKernelTitle,
+-		 const char * newKernelArgs, const char * newKernelInitrd,
+-		 const char ** extraInitrds, int extraInitrdCount,
+-                 const char * newMBKernel, const char * newMBKernelArgs,
+-		 const char * newDevTreePath) {
+-    struct singleEntry * new;
+-    struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
+-    int needs;
+-    char * chptr;
+-
+-    if (!newKernelPath) return 0;
+-
+-    /* if the newKernelTitle is too long silently munge it into something
+-     * we can live with. truncating is first check, then we'll just mess with
+-     * it until it looks better */
+-    if (config->cfi->maxTitleLength && 
++int addNewKernel(struct grubConfig *config, struct singleEntry *template,
++		 const char *prefix,
++		 const char *newKernelPath, const char *newKernelTitle,
++		 const char *newKernelArgs, const char *newKernelInitrd,
++		 const char **extraInitrds, int extraInitrdCount,
++		 const char *newMBKernel, const char *newMBKernelArgs,
++		 const char *newDevTreePath)
++{
++	struct singleEntry *new;
++	struct singleLine *newLine = NULL, *tmplLine = NULL, *masterLine = NULL;
++	int needs;
++	char *chptr;
++
++	if (!newKernelPath)
++		return 0;
++
++	/* if the newKernelTitle is too long silently munge it into something
++	 * we can live with. truncating is first check, then we'll just mess with
++	 * it until it looks better */
++	if (config->cfi->maxTitleLength &&
+ 	    (strlen(newKernelTitle) > config->cfi->maxTitleLength)) {
+-	char * buf = alloca(config->cfi->maxTitleLength + 7);
+-	char * numBuf = alloca(config->cfi->maxTitleLength + 1);
+-	int i = 1;
++		char *buf = alloca(config->cfi->maxTitleLength + 7);
++		char *numBuf = alloca(config->cfi->maxTitleLength + 1);
++		int i = 1;
+ 
+-	sprintf(buf, "TITLE=%.*s", config->cfi->maxTitleLength, newKernelTitle);
+-	while (findEntryByPath(config, buf, NULL, NULL)) {
+-	    sprintf(numBuf, "%d", i++);
+-	    strcpy(buf + strlen(buf) - strlen(numBuf), numBuf);
++		sprintf(buf, "TITLE=%.*s", config->cfi->maxTitleLength,
++			newKernelTitle);
++		while (findEntryByPath(config, buf, NULL, NULL)) {
++			sprintf(numBuf, "%d", i++);
++			strcpy(buf + strlen(buf) - strlen(numBuf), numBuf);
++		}
++
++		newKernelTitle = buf + 6;
+ 	}
+ 
+-	newKernelTitle = buf + 6;
+-    }
++	new = malloc(sizeof(*new));
++	new->skip = 0;
++	new->multiboot = 0;
++	new->next = config->entries;
++	new->lines = NULL;
++	config->entries = new;
+ 
+-    new = malloc(sizeof(*new));
+-    new->skip = 0;
+-    new->multiboot = 0;
+-    new->next = config->entries;
+-    new->lines = NULL;
+-    config->entries = new;
++	/* copy/update from the template */
++	needs = NEED_KERNEL | NEED_TITLE;
++	if (newKernelInitrd)
++		needs |= NEED_INITRD;
++	if (newMBKernel) {
++		needs |= NEED_MB;
++		new->multiboot = 1;
++	}
++	if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
++		needs |= NEED_DEVTREE;
+ 
+-    /* copy/update from the template */
+-    needs = NEED_KERNEL | NEED_TITLE;
+-    if (newKernelInitrd)
+-	needs |= NEED_INITRD;
+-    if (newMBKernel) {
+-        needs |= NEED_MB;
+-        new->multiboot = 1;
+-    }
+-    if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
+-	needs |= NEED_DEVTREE;
++	if (template) {
++		for (masterLine = template->lines;
++		     masterLine && (tmplLine = lineDup(masterLine));
++		     lineFree(tmplLine), masterLine = masterLine->next) {
++			dbgPrintf("addNewKernel processing %d\n",
++				  tmplLine->type);
+ 
+-    if (template) {
+-	for (masterLine = template->lines; 
+-	     masterLine && (tmplLine = lineDup(masterLine)); 
+-	     lineFree(tmplLine), masterLine = masterLine->next) 
+-	{
+-	    dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
++			/* skip comments */
++			chptr = tmplLine->indent;
++			while (*chptr && isspace(*chptr))
++				chptr++;
++			if (*chptr == '#')
++				continue;
+ 
+-	    /* skip comments */
+-	    chptr = tmplLine->indent;
+-	    while (*chptr && isspace(*chptr)) chptr++;
+-	    if (*chptr == '#') continue;
++			if (iskernel(tmplLine->type)
++			    && tmplLine->numElements >= 2) {
++				if (!template->multiboot && (needs & NEED_MB)) {
++					/* it's not a multiboot template and
++					 * this is the kernel line.  Try to
++					 * be intelligent about inserting the
++					 * hypervisor at the same time.
++					 */
++					if (config->cfi->mbHyperFirst) {
++						/* insert the hypervisor first */
++						newLine =
++						    addLine(new, config->cfi,
++							    LT_HYPER,
++							    tmplLine->indent,
++							    newMBKernel +
++							    strlen(prefix));
++						/* set up for adding the
++						 * kernel line */
++						free(tmplLine->indent);
++						tmplLine->indent =
++						    strdup(config->
++							   secondaryIndent);
++						needs &= ~NEED_MB;
++					}
++					if (needs & NEED_KERNEL) {
++						/* use addLineTmpl to
++						 * preserve line elements,
++						 * otherwise we could just
++						 * call addLine.
++						 * Unfortunately this means
++						 * making some changes to the
++						 * template such as the
++						 * indent change above and
++						 * the type change below.
++						 */
++						struct keywordTypes *mbm_kw =
++						    getKeywordByType
++						    (LT_MBMODULE, config->cfi);
++						if (mbm_kw) {
++							tmplLine->type =
++							    LT_MBMODULE;
++							free(tmplLine->
++							     elements[0].item);
++							tmplLine->elements[0].
++							    item =
++							    strdup(mbm_kw->key);
++						}
++						newLine =
++						    addLineTmpl(new, tmplLine,
++								newLine,
++								newKernelPath +
++								strlen(prefix),
++								config->cfi);
++						needs &= ~NEED_KERNEL;
++					}
++					if (needs & NEED_MB) {	/* !mbHyperFirst */
++						newLine =
++						    addLine(new, config->cfi,
++							    LT_HYPER,
++							    config->
++							    secondaryIndent,
++							    newMBKernel +
++							    strlen(prefix));
++						needs &= ~NEED_MB;
++					}
++				} else if (needs & NEED_KERNEL) {
++					newLine =
++					    addLineTmpl(new, tmplLine, newLine,
++							newKernelPath +
++							strlen(prefix),
++							config->cfi);
++					needs &= ~NEED_KERNEL;
++				}
+ 
+-	    if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
+-		if (!template->multiboot && (needs & NEED_MB)) {
+-		    /* it's not a multiboot template and this is the kernel
+-		     * line.  Try to be intelligent about inserting the
+-		     * hypervisor at the same time.
+-		     */
+-		    if (config->cfi->mbHyperFirst) {
+-			/* insert the hypervisor first */
+-			newLine = addLine(new, config->cfi, LT_HYPER, 
+-					  tmplLine->indent,
+-					  newMBKernel + strlen(prefix));
+-			/* set up for adding the kernel line */
+-			free(tmplLine->indent);
+-			tmplLine->indent = strdup(config->secondaryIndent);
+-			needs &= ~NEED_MB;
+-		    }
+-		    if (needs & NEED_KERNEL) {
+-			/* use addLineTmpl to preserve line elements,
+-			 * otherwise we could just call addLine.  Unfortunately
+-			 * this means making some changes to the template
+-			 * such as the indent change above and the type
+-			 * change below.
+-			 */
+-			struct keywordTypes * mbm_kw = 
+-			    getKeywordByType(LT_MBMODULE, config->cfi);
+-			if (mbm_kw) {
+-			    tmplLine->type = LT_MBMODULE;
+-			    free(tmplLine->elements[0].item);
+-			    tmplLine->elements[0].item = strdup(mbm_kw->key);
+-			}
+-			newLine = addLineTmpl(new, tmplLine, newLine,
+-					      newKernelPath + strlen(prefix), config->cfi);
+-			needs &= ~NEED_KERNEL;
+-		    }
+-		    if (needs & NEED_MB) { /* !mbHyperFirst */
+-			newLine = addLine(new, config->cfi, LT_HYPER, 
+-					  config->secondaryIndent,
+-					  newMBKernel + strlen(prefix));
+-			needs &= ~NEED_MB;
+-		    }
+-		} else if (needs & NEED_KERNEL) {
+-		    newLine = addLineTmpl(new, tmplLine, newLine, 
+-					  newKernelPath + strlen(prefix), config->cfi);
+-		    needs &= ~NEED_KERNEL;
+-		}
++			} else if (tmplLine->type == LT_HYPER &&
++				   tmplLine->numElements >= 2) {
++				if (needs & NEED_MB) {
++					newLine =
++					    addLineTmpl(new, tmplLine, newLine,
++							newMBKernel +
++							strlen(prefix),
++							config->cfi);
++					needs &= ~NEED_MB;
++				}
+ 
+-	    } else if (tmplLine->type == LT_HYPER && 
+-		       tmplLine->numElements >= 2) {
+-		if (needs & NEED_MB) {
+-		    newLine = addLineTmpl(new, tmplLine, newLine, 
+-					  newMBKernel + strlen(prefix), config->cfi);
+-		    needs &= ~NEED_MB;
+-		}
++			} else if (tmplLine->type == LT_MBMODULE &&
++				   tmplLine->numElements >= 2) {
++				if (new->multiboot) {
++					if (needs & NEED_KERNEL) {
++						newLine =
++						    addLineTmpl(new, tmplLine,
++								newLine,
++								newKernelPath +
++								strlen(prefix),
++								config->cfi);
++						needs &= ~NEED_KERNEL;
++					} else if (config->cfi->mbInitRdIsModule
++						   && (needs & NEED_INITRD)) {
++						char *initrdVal;
++						initrdVal =
++						    getInitrdVal(config, prefix,
++								 tmplLine,
++								 newKernelInitrd,
++								 extraInitrds,
++								 extraInitrdCount);
++						newLine =
++						    addLineTmpl(new, tmplLine,
++								newLine,
++								initrdVal,
++								config->cfi);
++						free(initrdVal);
++						needs &= ~NEED_INITRD;
++					}
++				} else if (needs & NEED_KERNEL) {
++					/* template is multi but new is not,
++					 * insert the kernel in the first
++					 * module slot
++					 */
++					tmplLine->type =
++					    preferredLineType(LT_KERNEL,
++							      config->cfi);
++					free(tmplLine->elements[0].item);
++					tmplLine->elements[0].item =
++					    strdup(getKeywordByType
++						   (tmplLine->type,
++						    config->cfi)->key);
++					newLine =
++					    addLineTmpl(new, tmplLine, newLine,
++							newKernelPath +
++							strlen(prefix),
++							config->cfi);
++					needs &= ~NEED_KERNEL;
++				} else if (needs & NEED_INITRD) {
++					char *initrdVal;
++					/* template is multi but new is not,
++					 * insert the initrd in the second
++					 * module slot
++					 */
++					tmplLine->type =
++					    preferredLineType(LT_INITRD,
++							      config->cfi);
++					free(tmplLine->elements[0].item);
++					tmplLine->elements[0].item =
++					    strdup(getKeywordByType
++						   (tmplLine->type,
++						    config->cfi)->key);
++					initrdVal =
++					    getInitrdVal(config, prefix,
++							 tmplLine,
++							 newKernelInitrd,
++							 extraInitrds,
++							 extraInitrdCount);
++					newLine =
++					    addLineTmpl(new, tmplLine, newLine,
++							initrdVal, config->cfi);
++					free(initrdVal);
++					needs &= ~NEED_INITRD;
++				}
+ 
+-	    } else if (tmplLine->type == LT_MBMODULE && 
+-		       tmplLine->numElements >= 2) {
+-		if (new->multiboot) {
+-		    if (needs & NEED_KERNEL) {
+-			newLine = addLineTmpl(new, tmplLine, newLine, 
+-					      newKernelPath + 
+-					      strlen(prefix), config->cfi);
+-			needs &= ~NEED_KERNEL;
+-		    } else if (config->cfi->mbInitRdIsModule &&
+-			       (needs & NEED_INITRD)) {
+-			char *initrdVal;
+-			initrdVal = getInitrdVal(config, prefix, tmplLine,
+-						 newKernelInitrd, extraInitrds,
+-						 extraInitrdCount);
+-			newLine = addLineTmpl(new, tmplLine, newLine,
+-					      initrdVal, config->cfi);
+-			free(initrdVal);
+-			needs &= ~NEED_INITRD;
+-		    }
+-		} else if (needs & NEED_KERNEL) {
+-		    /* template is multi but new is not, 
+-		     * insert the kernel in the first module slot
+-		     */
+-		    tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
+-		    free(tmplLine->elements[0].item);
+-		    tmplLine->elements[0].item = 
+-			strdup(getKeywordByType(tmplLine->type,
+-						config->cfi)->key);
+-		    newLine = addLineTmpl(new, tmplLine, newLine, 
+-					  newKernelPath + strlen(prefix),
+-					  config->cfi);
+-		    needs &= ~NEED_KERNEL;
+-		} else if (needs & NEED_INITRD) {
+-		    char *initrdVal;
+-		    /* template is multi but new is not,
+-		     * insert the initrd in the second module slot
+-		     */
+-		    tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
+-		    free(tmplLine->elements[0].item);
+-		    tmplLine->elements[0].item = 
+-			strdup(getKeywordByType(tmplLine->type,
+-						config->cfi)->key);
+-		    initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
+-		    newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
+-		    free(initrdVal);
+-		    needs &= ~NEED_INITRD;
+-		}
++			} else if (isinitrd(tmplLine->type)
++				   && tmplLine->numElements >= 2) {
++				if (needs & NEED_INITRD && new->multiboot
++				    && !template->multiboot
++				    && config->cfi->mbInitRdIsModule) {
++					/* make sure we don't insert the
++					 * module initrd before the module
++					 * kernel... if we don't do it here,
++					 * it will be inserted following the
++					 * template.
++					 */
++					if (!needs & NEED_KERNEL) {
++						char *initrdVal;
+ 
+-	    } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
+-		if (needs & NEED_INITRD &&
+-		    new->multiboot && !template->multiboot &&
+-		    config->cfi->mbInitRdIsModule) {
+-		    /* make sure we don't insert the module initrd
+-		     * before the module kernel... if we don't do it here,
+-		     * it will be inserted following the template.
+-		     */
+-		    if (!needs & NEED_KERNEL) {
+-			char *initrdVal;
+-	
+-			initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
+-			newLine = addLine(new, config->cfi, LT_MBMODULE,
+-					  config->secondaryIndent, 
+-					  initrdVal);
+-			free(initrdVal);
+-			needs &= ~NEED_INITRD;
+-		    }
+-		} else if (needs & NEED_INITRD) {
+-		    char *initrdVal;
+-		    initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
+-		    newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
+-		    free(initrdVal);
+-		    needs &= ~NEED_INITRD;
+-		}
++						initrdVal =
++						    getInitrdVal(config, prefix,
++								 tmplLine,
++								 newKernelInitrd,
++								 extraInitrds,
++								 extraInitrdCount);
++						newLine =
++						    addLine(new, config->cfi,
++							    LT_MBMODULE,
++							    config->
++							    secondaryIndent,
++							    initrdVal);
++						free(initrdVal);
++						needs &= ~NEED_INITRD;
++					}
++				} else if (needs & NEED_INITRD) {
++					char *initrdVal;
++					initrdVal =
++					    getInitrdVal(config, prefix,
++							 tmplLine,
++							 newKernelInitrd,
++							 extraInitrds,
++							 extraInitrdCount);
++					newLine =
++					    addLineTmpl(new, tmplLine, newLine,
++							initrdVal, config->cfi);
++					free(initrdVal);
++					needs &= ~NEED_INITRD;
++				}
+ 
+-	    } else if (tmplLine->type == LT_MENUENTRY &&
+-		       (needs & NEED_TITLE)) {
+-		requote(tmplLine, config->cfi);
+-		char *nkt = malloc(strlen(newKernelTitle)+3);
+-		strcpy(nkt, "'");
+-		strcat(nkt, newKernelTitle);
+-		strcat(nkt, "'");
+-		newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
+-		free(nkt);
+-		needs &= ~NEED_TITLE;
+-	    } else if (tmplLine->type == LT_TITLE && 
+-		       (needs & NEED_TITLE)) {
+-		if (tmplLine->numElements >= 2) {
+-		    newLine = addLineTmpl(new, tmplLine, newLine, 
+-					  newKernelTitle, config->cfi);
+-		    needs &= ~NEED_TITLE;
+-		} else if (tmplLine->numElements == 1 &&
+-			   config->cfi->titleBracketed) {
+-		    /* addLineTmpl doesn't handle titleBracketed */
+-		    newLine = addLine(new, config->cfi, LT_TITLE,
+-				      tmplLine->indent, newKernelTitle);
+-		    needs &= ~NEED_TITLE;
+-		}
+-	    } else if (tmplLine->type == LT_ECHO) {
+-		    requote(tmplLine, config->cfi);
+-		    static const char *prefix = "'Loading ";
+-		    if (tmplLine->numElements > 1 &&
+-			    strstr(tmplLine->elements[1].item, prefix) &&
+-			    masterLine->next &&
+-			    iskernel(masterLine->next->type)) {
+-			char *newTitle = malloc(strlen(prefix) +
+-						strlen(newKernelTitle) + 2);
+-
+-			strcpy(newTitle, prefix);
+-			strcat(newTitle, newKernelTitle);
+-			strcat(newTitle, "'");
+-			newLine = addLine(new, config->cfi, LT_ECHO,
+-					tmplLine->indent, newTitle);
+-			free(newTitle);
+-		    } else {
+-			/* pass through other lines from the template */
+-			newLine = addLineTmpl(new, tmplLine, newLine, NULL,
++			} else if (tmplLine->type == LT_MENUENTRY &&
++				   (needs & NEED_TITLE)) {
++				requote(tmplLine, config->cfi);
++				char *nkt = malloc(strlen(newKernelTitle) + 3);
++				strcpy(nkt, "'");
++				strcat(nkt, newKernelTitle);
++				strcat(nkt, "'");
++				newLine =
++				    addLineTmpl(new, tmplLine, newLine, nkt,
+ 						config->cfi);
+-		    }
+-	    } else if (tmplLine->type == LT_DEVTREE &&
+-		       tmplLine->numElements == 2 && newDevTreePath) {
+-	        newLine = addLineTmpl(new, tmplLine, newLine,
+-				      newDevTreePath + strlen(prefix),
+-				      config->cfi);
+-		needs &= ~NEED_DEVTREE;
+-	    } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
+-		const char *ndtp = newDevTreePath;
+-		if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
+-		    ndtp += strlen(prefix);
+-		newLine = addLine(new, config->cfi, LT_DEVTREE,
+-				  config->secondaryIndent,
+-				  ndtp);
+-		needs &= ~NEED_DEVTREE;
+-		newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
+-	    } else {
+-		/* pass through other lines from the template */
+-		newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
+-	    }
+-	}
++				free(nkt);
++				needs &= ~NEED_TITLE;
++			} else if (tmplLine->type == LT_TITLE &&
++				   (needs & NEED_TITLE)) {
++				if (tmplLine->numElements >= 2) {
++					newLine =
++					    addLineTmpl(new, tmplLine, newLine,
++							newKernelTitle,
++							config->cfi);
++					needs &= ~NEED_TITLE;
++				} else if (tmplLine->numElements == 1 &&
++					   config->cfi->titleBracketed) {
++					/* addLineTmpl doesn't handle
++					 * titleBracketed */
++					newLine =
++					    addLine(new, config->cfi, LT_TITLE,
++						    tmplLine->indent,
++						    newKernelTitle);
++					needs &= ~NEED_TITLE;
++				}
++			} else if (tmplLine->type == LT_ECHO) {
++				requote(tmplLine, config->cfi);
++				static const char *prefix = "'Loading ";
++				if (tmplLine->numElements > 1 &&
++				    strstr(tmplLine->elements[1].item, prefix)
++				    && masterLine->next
++				    && iskernel(masterLine->next->type)) {
++					char *newTitle =
++					    malloc(strlen(prefix) +
++						   strlen(newKernelTitle) + 2);
+ 
+-    } else {
+-	/* don't have a template, so start the entry with the 
+-	 * appropriate starting line 
+-	 */
+-	switch (config->cfi->entryStart) {
+-	    case LT_KERNEL:
+-	    case LT_KERNEL_EFI:
+-	    case LT_KERNEL_16:
+-		if (new->multiboot && config->cfi->mbHyperFirst) {
+-		    /* fall through to LT_HYPER */
+-		} else {
+-		    newLine = addLine(new, config->cfi,
+-		    		      preferredLineType(LT_KERNEL, config->cfi),
+-				      config->primaryIndent,
+-				      newKernelPath + strlen(prefix));
+-		    needs &= ~NEED_KERNEL;
+-		    break;
++					strcpy(newTitle, prefix);
++					strcat(newTitle, newKernelTitle);
++					strcat(newTitle, "'");
++					newLine =
++					    addLine(new, config->cfi, LT_ECHO,
++						    tmplLine->indent, newTitle);
++					free(newTitle);
++				} else {
++					/* pass through other lines from the
++					 * template */
++					newLine =
++					    addLineTmpl(new, tmplLine, newLine,
++							NULL, config->cfi);
++				}
++			} else if (tmplLine->type == LT_DEVTREE &&
++				   tmplLine->numElements == 2
++				   && newDevTreePath) {
++				newLine =
++				    addLineTmpl(new, tmplLine, newLine,
++						newDevTreePath + strlen(prefix),
++						config->cfi);
++				needs &= ~NEED_DEVTREE;
++			} else if (tmplLine->type == LT_ENTRY_END
++				   && needs & NEED_DEVTREE) {
++				const char *ndtp = newDevTreePath;
++				if (!strncmp
++				    (newDevTreePath, prefix, strlen(prefix)))
++					ndtp += strlen(prefix);
++				newLine = addLine(new, config->cfi, LT_DEVTREE,
++						  config->secondaryIndent,
++						  ndtp);
++				needs &= ~NEED_DEVTREE;
++				newLine =
++				    addLineTmpl(new, tmplLine, newLine, NULL,
++						config->cfi);
++			} else {
++				/* pass through other lines from the template */
++				newLine =
++				    addLineTmpl(new, tmplLine, newLine, NULL,
++						config->cfi);
++			}
+ 		}
+ 
+-	    case LT_HYPER:
+-		newLine = addLine(new, config->cfi, LT_HYPER,
+-				  config->primaryIndent,
+-				  newMBKernel + strlen(prefix));
+-		needs &= ~NEED_MB;
+-		break;
++	} else {
++		/* don't have a template, so start the entry with the 
++		 * appropriate starting line 
++		 */
++		switch (config->cfi->entryStart) {
++		case LT_KERNEL:
++		case LT_KERNEL_EFI:
++		case LT_KERNEL_16:
++			if (new->multiboot && config->cfi->mbHyperFirst) {
++				/* fall through to LT_HYPER */
++			} else {
++				newLine = addLine(new, config->cfi,
++						  preferredLineType(LT_KERNEL,
++								    config->
++								    cfi),
++						  config->primaryIndent,
++						  newKernelPath +
++						  strlen(prefix));
++				needs &= ~NEED_KERNEL;
++				break;
++			}
++
++		case LT_HYPER:
++			newLine = addLine(new, config->cfi, LT_HYPER,
++					  config->primaryIndent,
++					  newMBKernel + strlen(prefix));
++			needs &= ~NEED_MB;
++			break;
++
++		case LT_MENUENTRY:{
++				char *nkt = malloc(strlen(newKernelTitle) + 3);
++				strcpy(nkt, "'");
++				strcat(nkt, newKernelTitle);
++				strcat(nkt, "'");
++				newLine =
++				    addLine(new, config->cfi, LT_MENUENTRY,
++					    config->primaryIndent, nkt);
++				free(nkt);
++				needs &= ~NEED_TITLE;
++				needs |= NEED_END;
++				break;
++			}
++		case LT_TITLE:
++			if (useextlinuxmenu != 0) {	// We just need useextlinuxmenu to not be zero (set above)
++				char *templabel;
++				int x = 0, y = 0;
++
++				templabel = strdup(newKernelTitle);
++				while (templabel[x]) {
++					if (templabel[x] == ' ') {
++						y = x;
++						while (templabel[y]) {
++							templabel[y] =
++							    templabel[y + 1];
++							y++;
++						}
++					}
++					x++;
++				}
++				newLine = addLine(new, config->cfi, LT_TITLE,
++						  config->primaryIndent,
++						  templabel);
++				free(templabel);
++			} else {
++				newLine = addLine(new, config->cfi, LT_TITLE,
++						  config->primaryIndent,
++						  newKernelTitle);
++			}
++			needs &= ~NEED_TITLE;
++			break;
++
++		default:
++			abort();
++		}
++	}
+ 
+-	    case LT_MENUENTRY: {
+-		char *nkt = malloc(strlen(newKernelTitle)+3);
+-		strcpy(nkt, "'");
+-		strcat(nkt, newKernelTitle);
+-		strcat(nkt, "'");
+-	        newLine = addLine(new, config->cfi, LT_MENUENTRY,
+-				  config->primaryIndent, nkt);
+-		free(nkt);
+-		needs &= ~NEED_TITLE;
++	struct singleLine *endLine = NULL;
++	endLine = getLineByType(LT_ENTRY_END, new->lines);
++	if (endLine) {
++		removeLine(new, endLine);
+ 		needs |= NEED_END;
+-		break;
+-	    }
+-	    case LT_TITLE:
+-		if( useextlinuxmenu != 0 ){	// We just need useextlinuxmenu to not be zero (set above)
+-			char * templabel;
+-			int x = 0, y = 0;
++	}
+ 
+-			templabel = strdup(newKernelTitle);
+-			while( templabel[x]){
+-				if( templabel[x] == ' ' ){
+-					y = x;
+-					while( templabel[y] ){
+-						templabel[y] = templabel[y+1];
+-						y++;
+-					}
+-				}
+-				x++;
+-			}
+-			newLine = addLine(new, config->cfi, LT_TITLE,
+-					  config->primaryIndent, templabel);
+-			free(templabel);
+-		}else{
+-			newLine = addLine(new, config->cfi, LT_TITLE,
+-					  config->primaryIndent, newKernelTitle);
+-		}
++	/* add the remainder of the lines, i.e. those that either
++	 * weren't present in the template, or in the case of no template,
++	 * all the lines following the entryStart.
++	 */
++	if (needs & NEED_TITLE) {
++		newLine = addLine(new, config->cfi, LT_TITLE,
++				  config->secondaryIndent, newKernelTitle);
+ 		needs &= ~NEED_TITLE;
+-		break;
++	}
++	if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
++		newLine = addLine(new, config->cfi, LT_HYPER,
++				  config->secondaryIndent,
++				  newMBKernel + strlen(prefix));
++		needs &= ~NEED_MB;
++	}
++	if (needs & NEED_KERNEL) {
++		newLine = addLine(new, config->cfi,
++				  (new->multiboot
++				   && getKeywordByType(LT_MBMODULE,
++						       config->cfi))
++				  ? LT_MBMODULE : preferredLineType(LT_KERNEL,
++								    config->
++								    cfi),
++				  config->secondaryIndent,
++				  newKernelPath + strlen(prefix));
++		needs &= ~NEED_KERNEL;
++	}
++	if (needs & NEED_MB) {
++		newLine = addLine(new, config->cfi, LT_HYPER,
++				  config->secondaryIndent,
++				  newMBKernel + strlen(prefix));
++		needs &= ~NEED_MB;
++	}
++	if (needs & NEED_INITRD) {
++		char *initrdVal;
++		initrdVal =
++		    getInitrdVal(config, prefix, NULL, newKernelInitrd,
++				 extraInitrds, extraInitrdCount);
++		newLine =
++		    addLine(new, config->cfi,
++			    (new->multiboot
++			     && getKeywordByType(LT_MBMODULE, config->cfi))
++			    ? LT_MBMODULE : preferredLineType(LT_INITRD,
++							      config->cfi),
++			    config->secondaryIndent, initrdVal);
++		free(initrdVal);
++		needs &= ~NEED_INITRD;
++	}
++	if (needs & NEED_DEVTREE) {
++		newLine = addLine(new, config->cfi, LT_DEVTREE,
++				  config->secondaryIndent, newDevTreePath);
++		needs &= ~NEED_DEVTREE;
++	}
+ 
+-	    default:
++	/* NEEDS_END must be last on bootloaders that need it... */
++	if (needs & NEED_END) {
++		newLine = addLine(new, config->cfi, LT_ENTRY_END,
++				  config->secondaryIndent, NULL);
++		needs &= ~NEED_END;
++	}
++
++	if (needs) {
++		printf(_("grubby: needs=%d, aborting\n"), needs);
+ 		abort();
+ 	}
+-    } 
+ 
+-    struct singleLine *endLine = NULL;
+-    endLine = getLineByType(LT_ENTRY_END, new->lines);
+-    if (endLine) {
+-	    removeLine(new, endLine);
+-	    needs |= NEED_END;
+-    }
++	if (updateImage(config, "0", prefix, newKernelArgs, NULL,
++			newMBKernelArgs, NULL))
++		return 1;
+ 
+-    /* add the remainder of the lines, i.e. those that either
+-     * weren't present in the template, or in the case of no template,
+-     * all the lines following the entryStart.
+-     */
+-    if (needs & NEED_TITLE) {
+-	newLine = addLine(new, config->cfi, LT_TITLE, 
+-			  config->secondaryIndent, 
+-			  newKernelTitle);
+-	needs &= ~NEED_TITLE;
+-    }
+-    if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
+-	newLine = addLine(new, config->cfi, LT_HYPER, 
+-			  config->secondaryIndent, 
+-			  newMBKernel + strlen(prefix));
+-	needs &= ~NEED_MB;
+-    }
+-    if (needs & NEED_KERNEL) {
+-	newLine = addLine(new, config->cfi, 
+-			  (new->multiboot && getKeywordByType(LT_MBMODULE, 
+-							      config->cfi))
+-			  	? LT_MBMODULE
+-				: preferredLineType(LT_KERNEL, config->cfi),
+-			  config->secondaryIndent, 
+-			  newKernelPath + strlen(prefix));
+-	needs &= ~NEED_KERNEL;
+-    }
+-    if (needs & NEED_MB) {
+-	newLine = addLine(new, config->cfi, LT_HYPER, 
+-			  config->secondaryIndent,
+-			  newMBKernel + strlen(prefix));
+-	needs &= ~NEED_MB;
+-    }
+-    if (needs & NEED_INITRD) {
+-	char *initrdVal;
+-	initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
+-	newLine = addLine(new, config->cfi,
+-			  (new->multiboot && getKeywordByType(LT_MBMODULE,
+-							      config->cfi))
+-			   ? LT_MBMODULE
+-			   : preferredLineType(LT_INITRD, config->cfi), 
+-			  config->secondaryIndent, 
+-			  initrdVal);
+-	free(initrdVal);
+-	needs &= ~NEED_INITRD;
+-    }
+-    if (needs & NEED_DEVTREE) {
+-	newLine = addLine(new, config->cfi, LT_DEVTREE,
+-			  config->secondaryIndent,
+-			  newDevTreePath);
+-	needs &= ~NEED_DEVTREE;
+-    }
+-
+-    /* NEEDS_END must be last on bootloaders that need it... */
+-    if (needs & NEED_END) {
+-	newLine = addLine(new, config->cfi, LT_ENTRY_END,
+-			config->secondaryIndent, NULL);
+-	needs &= ~NEED_END;
+-    }
+-
+-    if (needs) {
+-	printf(_("grubby: needs=%d, aborting\n"), needs);
+-	abort();
+-    }
+-
+-    if (updateImage(config, "0", prefix, newKernelArgs, NULL, 
+-                    newMBKernelArgs, NULL)) return 1;
+-
+-    return 0;
++	return 0;
+ }
+ 
+-int main(int argc, const char ** argv) {
+-    poptContext optCon;
+-    const char * grubConfig = NULL;
+-    char * outputFile = NULL;
+-    int arg = 0;
+-    int flags = 0;
+-    int badImageOkay = 0;
+-    int configureGrub2 = 0;
+-    int configureLilo = 0, configureELilo = 0, configureGrub = 0;
+-    int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
+-    int configureExtLinux = 0;
+-    int bootloaderProbe = 0;
+-    int extraInitrdCount = 0;
+-    char * updateKernelPath = NULL;
+-    char * newKernelPath = NULL;
+-    char * removeKernelPath = NULL;
+-    char * newKernelArgs = NULL;
+-    char * newKernelInitrd = NULL;
+-    char * newKernelTitle = NULL;
+-    char * newDevTreePath = NULL;
+-    char * newMBKernel = NULL;
+-    char * newMBKernelArgs = NULL;
+-    char * removeMBKernelArgs = NULL;
+-    char * removeMBKernel = NULL;
+-    char * bootPrefix = NULL;
+-    char * defaultKernel = NULL;
+-    char * removeArgs = NULL;
+-    char * kernelInfo = NULL;
+-    char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
+-    char * envPath = NULL;
+-    const char * chptr = NULL;
+-    struct configFileInfo * cfi = NULL;
+-    struct grubConfig * config;
+-    struct singleEntry * template = NULL;
+-    int copyDefault = 0, makeDefault = 0;
+-    int displayDefault = 0;
+-    int displayDefaultIndex = 0;
+-    int displayDefaultTitle = 0;
+-    int defaultIndex = -1;
+-    struct poptOption options[] = {
+-	{ "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
+-	    _("add an entry for the specified kernel"), _("kernel-path") },
+-	{ "add-multiboot", 0, POPT_ARG_STRING, &newMBKernel, 0,
+-	    _("add an entry for the specified multiboot kernel"), NULL },
+-	{ "args", 0, POPT_ARG_STRING, &newKernelArgs, 0, 
+-	    _("default arguments for the new kernel or new arguments for "
+-	      "kernel being updated"), _("args") },
+-	{ "mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0, 
+-	    _("default arguments for the new multiboot kernel or "
+-              "new arguments for multiboot kernel being updated"), NULL },
+-	{ "bad-image-okay", 0, 0, &badImageOkay, 0,
+-	    _("don't sanity check images in boot entries (for testing only)"), 
+-	    NULL },
+-	{ "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
+-	    _("filestystem which contains /boot directory (for testing only)"),
+-	    _("bootfs") },
++int main(int argc, const char **argv)
++{
++	poptContext optCon;
++	const char *grubConfig = NULL;
++	char *outputFile = NULL;
++	int arg = 0;
++	int flags = 0;
++	int badImageOkay = 0;
++	int configureGrub2 = 0;
++	int configureLilo = 0, configureELilo = 0, configureGrub = 0;
++	int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
++	int configureExtLinux = 0;
++	int bootloaderProbe = 0;
++	int extraInitrdCount = 0;
++	char *updateKernelPath = NULL;
++	char *newKernelPath = NULL;
++	char *removeKernelPath = NULL;
++	char *newKernelArgs = NULL;
++	char *newKernelInitrd = NULL;
++	char *newKernelTitle = NULL;
++	char *newDevTreePath = NULL;
++	char *newMBKernel = NULL;
++	char *newMBKernelArgs = NULL;
++	char *removeMBKernelArgs = NULL;
++	char *removeMBKernel = NULL;
++	char *bootPrefix = NULL;
++	char *defaultKernel = NULL;
++	char *removeArgs = NULL;
++	char *kernelInfo = NULL;
++	char *extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
++	char *envPath = NULL;
++	const char *chptr = NULL;
++	struct configFileInfo *cfi = NULL;
++	struct grubConfig *config;
++	struct singleEntry *template = NULL;
++	int copyDefault = 0, makeDefault = 0;
++	int displayDefault = 0;
++	int displayDefaultIndex = 0;
++	int displayDefaultTitle = 0;
++	int defaultIndex = -1;
++	struct poptOption options[] = {
++		{"add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
++		 _("add an entry for the specified kernel"), _("kernel-path")},
++		{"add-multiboot", 0, POPT_ARG_STRING, &newMBKernel, 0,
++		 _("add an entry for the specified multiboot kernel"), NULL},
++		{"args", 0, POPT_ARG_STRING, &newKernelArgs, 0,
++		 _("default arguments for the new kernel or new arguments for "
++		   "kernel being updated"), _("args")},
++		{"mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0,
++		 _("default arguments for the new multiboot kernel or "
++		   "new arguments for multiboot kernel being updated"), NULL},
++		{"bad-image-okay", 0, 0, &badImageOkay, 0,
++		 _
++		 ("don't sanity check images in boot entries (for testing only)"),
++		 NULL},
++		{"boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
++		 _
++		 ("filestystem which contains /boot directory (for testing only)"),
++		 _("bootfs")},
+ #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
+-	{ "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
+-	    _("check which bootloader is installed on boot sector") },
++		{"bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
++		 _("check which bootloader is installed on boot sector")},
+ #endif
+-	{ "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
+-	    _("path to grub config file to update (\"-\" for stdin)"), 
+-	    _("path") },
+-	{ "copy-default", 0, 0, &copyDefault, 0,
+-	    _("use the default boot entry as a template for the new entry "
+-	      "being added; if the default is not a linux image, or if "
+-	      "the kernel referenced by the default image does not exist, "
+-	      "the first linux entry whose kernel does exist is used as the "
+-	      "template"), NULL },
+-	{ "debug", 0, 0, &debug, 0,
+-	    _("print debugging information for failures") },
+-	{ "default-kernel", 0, 0, &displayDefault, 0,
+-	    _("display the path of the default kernel") },
+-	{ "default-index", 0, 0, &displayDefaultIndex, 0,
+-	    _("display the index of the default kernel") },
+-	{ "default-title", 0, 0, &displayDefaultTitle, 0,
+-	    _("display the title of the default kernel") },
+-	{ "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
+-	    _("device tree file for new stanza"), _("dtb-path") },
+-	{ "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
+-	    _("device tree directory for new stanza"), _("dtb-path") },
+-	{ "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
+-	    _("configure elilo bootloader") },
+-	{ "efi", 0, POPT_ARG_NONE, &isEfi, 0,
+-	    _("force grub2 stanzas to use efi") },
+-	{ "env", 0, POPT_ARG_STRING, &envPath, 0,
+-	    _("path for environment data"),
+-	    _("path") },
+-	{ "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
+-	    _("configure extlinux bootloader (from syslinux)") },
+-	{ "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
+-	    _("configure grub bootloader") },
+-	{ "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
+-	    _("configure grub2 bootloader") },
+-	{ "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
+-	    _("display boot information for specified kernel"),
+-	    _("kernel-path") },
+-	{ "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
+-	    _("initrd image for the new kernel"), _("initrd-path") },
+-	{ "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
+-	    _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
+-	{ "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
+-	    _("configure lilo bootloader") },
+-	{ "make-default", 0, 0, &makeDefault, 0,
+-	    _("make the newly added entry the default boot entry"), NULL },
+-	{ "output-file", 'o', POPT_ARG_STRING, &outputFile, 0,
+-	    _("path to output updated config file (\"-\" for stdout)"), 
+-	    _("path") },
+-	{ "remove-args", 0, POPT_ARG_STRING, &removeArgs, 0,
+-            _("remove kernel arguments"), NULL },
+-        { "remove-mbargs", 0, POPT_ARG_STRING, &removeMBKernelArgs, 0,
+-	    _("remove multiboot kernel arguments"), NULL },
+-	{ "remove-kernel", 0, POPT_ARG_STRING, &removeKernelPath, 0,
+-	    _("remove all entries for the specified kernel"), 
+-	    _("kernel-path") },
+-	{ "remove-multiboot", 0, POPT_ARG_STRING, &removeMBKernel, 0,
+-            _("remove all entries for the specified multiboot kernel"), NULL },
+-	{ "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
+-	    _("make the first entry referencing the specified kernel "
+-	      "the default"), _("kernel-path") },
+-	{ "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
+-	    _("make the given entry index the default entry"),
+-	    _("entry-index") },
+-	{ "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
+-	    _("configure silo bootloader") },
+-	{ "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
+-	    _("title to use for the new kernel entry"), _("entry-title") },
+-	{ "update-kernel", 0, POPT_ARG_STRING, &updateKernelPath, 0,
+-	    _("updated information for the specified kernel"), 
+-	    _("kernel-path") },
+-	{ "version", 'v', 0, NULL, 'v',
+-	    _("print the version of this program and exit"), NULL },
+-	{ "yaboot", 0, POPT_ARG_NONE, &configureYaboot, 0,
+-	    _("configure yaboot bootloader") },
+-	{ "zipl", 0, POPT_ARG_NONE, &configureZipl, 0,
+-	    _("configure zipl bootloader") },
+-	POPT_AUTOHELP
+-	{ 0, 0, 0, 0, 0 }
+-    };
++		{"config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
++		 _("path to grub config file to update (\"-\" for stdin)"),
++		 _("path")},
++		{"copy-default", 0, 0, &copyDefault, 0,
++		 _("use the default boot entry as a template for the new entry "
++		   "being added; if the default is not a linux image, or if "
++		   "the kernel referenced by the default image does not exist, "
++		   "the first linux entry whose kernel does exist is used as the "
++		   "template"), NULL},
++		{"debug", 0, 0, &debug, 0,
++		 _("print debugging information for failures")},
++		{"default-kernel", 0, 0, &displayDefault, 0,
++		 _("display the path of the default kernel")},
++		{"default-index", 0, 0, &displayDefaultIndex, 0,
++		 _("display the index of the default kernel")},
++		{"default-title", 0, 0, &displayDefaultTitle, 0,
++		 _("display the title of the default kernel")},
++		{"devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
++		 _("device tree file for new stanza"), _("dtb-path")},
++		{"devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
++		 _("device tree directory for new stanza"), _("dtb-path")},
++		{"elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
++		 _("configure elilo bootloader")},
++		{"efi", 0, POPT_ARG_NONE, &isEfi, 0,
++		 _("force grub2 stanzas to use efi")},
++		{"env", 0, POPT_ARG_STRING, &envPath, 0,
++		 _("path for environment data"),
++		 _("path")},
++		{"extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
++		 _("configure extlinux bootloader (from syslinux)")},
++		{"grub", 0, POPT_ARG_NONE, &configureGrub, 0,
++		 _("configure grub bootloader")},
++		{"grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
++		 _("configure grub2 bootloader")},
++		{"info", 0, POPT_ARG_STRING, &kernelInfo, 0,
++		 _("display boot information for specified kernel"),
++		 _("kernel-path")},
++		{"initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
++		 _("initrd image for the new kernel"), _("initrd-path")},
++		{"extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
++		 _
++		 ("auxiliary initrd image for things other than the new kernel"),
++		 _("initrd-path")},
++		{"lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
++		 _("configure lilo bootloader")},
++		{"make-default", 0, 0, &makeDefault, 0,
++		 _("make the newly added entry the default boot entry"), NULL},
++		{"output-file", 'o', POPT_ARG_STRING, &outputFile, 0,
++		 _("path to output updated config file (\"-\" for stdout)"),
++		 _("path")},
++		{"remove-args", 0, POPT_ARG_STRING, &removeArgs, 0,
++		 _("remove kernel arguments"), NULL},
++		{"remove-mbargs", 0, POPT_ARG_STRING, &removeMBKernelArgs, 0,
++		 _("remove multiboot kernel arguments"), NULL},
++		{"remove-kernel", 0, POPT_ARG_STRING, &removeKernelPath, 0,
++		 _("remove all entries for the specified kernel"),
++		 _("kernel-path")},
++		{"remove-multiboot", 0, POPT_ARG_STRING, &removeMBKernel, 0,
++		 _("remove all entries for the specified multiboot kernel"),
++		 NULL},
++		{"set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
++		 _("make the first entry referencing the specified kernel "
++		   "the default"), _("kernel-path")},
++		{"set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
++		 _("make the given entry index the default entry"),
++		 _("entry-index")},
++		{"silo", 0, POPT_ARG_NONE, &configureSilo, 0,
++		 _("configure silo bootloader")},
++		{"title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
++		 _("title to use for the new kernel entry"), _("entry-title")},
++		{"update-kernel", 0, POPT_ARG_STRING, &updateKernelPath, 0,
++		 _("updated information for the specified kernel"),
++		 _("kernel-path")},
++		{"version", 'v', 0, NULL, 'v',
++		 _("print the version of this program and exit"), NULL},
++		{"yaboot", 0, POPT_ARG_NONE, &configureYaboot, 0,
++		 _("configure yaboot bootloader")},
++		{"zipl", 0, POPT_ARG_NONE, &configureZipl, 0,
++		 _("configure zipl bootloader")},
++		POPT_AUTOHELP {0, 0, 0, 0, 0}
++	};
+ 
+-    useextlinuxmenu=0;
++	useextlinuxmenu = 0;
+ 
+-    int i = 0;
+-    for (int j = 1; j < argc; j++)
+-	i += strlen(argv[j]) + 1;
+-    saved_command_line = malloc(i);
+-    if (!saved_command_line) {
+-	fprintf(stderr, "grubby: %m\n");
+-	exit(1);
+-    }
+-    saved_command_line[0] = '\0';
+-    for (int j = 1; j < argc; j++) {
+-	strcat(saved_command_line, argv[j]);
+-	strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
+-    }
++	int i = 0;
++	for (int j = 1; j < argc; j++)
++		i += strlen(argv[j]) + 1;
++	saved_command_line = malloc(i);
++	if (!saved_command_line) {
++		fprintf(stderr, "grubby: %m\n");
++		exit(1);
++	}
++	saved_command_line[0] = '\0';
++	for (int j = 1; j < argc; j++) {
++		strcat(saved_command_line, argv[j]);
++		strncat(saved_command_line, j == argc - 1 ? "" : " ", 1);
++	}
+ 
+-    optCon = poptGetContext("grubby", argc, argv, options, 0);
+-    poptReadDefaultConfig(optCon, 1);
++	optCon = poptGetContext("grubby", argc, argv, options, 0);
++	poptReadDefaultConfig(optCon, 1);
+ 
+-    while ((arg = poptGetNextOpt(optCon)) >= 0) {
+-	switch (arg) {
+-	  case 'v':
+-	    printf("grubby version %s\n", VERSION);
+-	    exit(0);
+-	    break;
+-	  case 'i':
+-	    if (extraInitrdCount < MAX_EXTRA_INITRDS) {
+-	    	extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
+-	    } else {
+-		fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
+-		return 1;
+-	    }
+-	    break;
++	while ((arg = poptGetNextOpt(optCon)) >= 0) {
++		switch (arg) {
++		case 'v':
++			printf("grubby version %s\n", VERSION);
++			exit(0);
++			break;
++		case 'i':
++			if (extraInitrdCount < MAX_EXTRA_INITRDS) {
++				extraInitrds[extraInitrdCount++] =
++				    strdup(poptGetOptArg(optCon));
++			} else {
++				fprintf(stderr,
++					_
++					("grubby: extra initrd maximum is %d\n"),
++					extraInitrdCount);
++				return 1;
++			}
++			break;
++		}
+ 	}
+-    }
+ 
+-    if (arg < -1) {
+-	fprintf(stderr, _("grubby: bad argument %s: %s\n"),
+-		poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+-		poptStrerror(arg));
+-	return 1;
+-    }
++	if (arg < -1) {
++		fprintf(stderr, _("grubby: bad argument %s: %s\n"),
++			poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
++			poptStrerror(arg));
++		return 1;
++	}
+ 
+-    if ((chptr = poptGetArg(optCon))) {
+-	fprintf(stderr, _("grubby: unexpected argument %s\n"), chptr);
+-	return 1;
+-    }
++	if ((chptr = poptGetArg(optCon))) {
++		fprintf(stderr, _("grubby: unexpected argument %s\n"), chptr);
++		return 1;
++	}
+ 
+-    if ((configureLilo + configureGrub2 + configureGrub + configureELilo + 
+-		configureYaboot + configureSilo + configureZipl +
+-		configureExtLinux ) > 1) {
+-	fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
+-	return 1;
+-    } else if (bootloaderProbe && grubConfig) {
+-	fprintf(stderr, 
+-	    _("grubby: cannot specify config file with --bootloader-probe\n"));
+-	return 1;
+-    } else if (configureGrub2) {
+-	cfi = &grub2ConfigType;
+-	if (envPath)
+-	    cfi->envFile = envPath;
+-    } else if (configureLilo) {
+-	cfi = &liloConfigType;
+-    } else if (configureGrub) {
+-	cfi = &grubConfigType;
+-    } else if (configureELilo) {
+-	cfi = &eliloConfigType;
+-    } else if (configureYaboot) {
+-	cfi = &yabootConfigType;
+-    } else if (configureSilo) {
+-        cfi = &siloConfigType;
+-    } else if (configureZipl) {
+-        cfi = &ziplConfigType;
+-    } else if (configureExtLinux) {
+-	cfi = &extlinuxConfigType;
+-	useextlinuxmenu=1;
+-    }
++	if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
++	     configureYaboot + configureSilo + configureZipl +
++	     configureExtLinux) > 1) {
++		fprintf(stderr,
++			_("grubby: cannot specify multiple bootloaders\n"));
++		return 1;
++	} else if (bootloaderProbe && grubConfig) {
++		fprintf(stderr,
++			_
++			("grubby: cannot specify config file with --bootloader-probe\n"));
++		return 1;
++	} else if (configureGrub2) {
++		cfi = &grub2ConfigType;
++		if (envPath)
++			cfi->envFile = envPath;
++	} else if (configureLilo) {
++		cfi = &liloConfigType;
++	} else if (configureGrub) {
++		cfi = &grubConfigType;
++	} else if (configureELilo) {
++		cfi = &eliloConfigType;
++	} else if (configureYaboot) {
++		cfi = &yabootConfigType;
++	} else if (configureSilo) {
++		cfi = &siloConfigType;
++	} else if (configureZipl) {
++		cfi = &ziplConfigType;
++	} else if (configureExtLinux) {
++		cfi = &extlinuxConfigType;
++		useextlinuxmenu = 1;
++	}
+ 
+-    if (!cfi) {
+-        if (grub2FindConfig(&grub2ConfigType)) {
+-	    cfi = &grub2ConfigType;
+-	    if (envPath)
+-		cfi->envFile = envPath;
+-        } else
+-      #ifdef __ia64__
+-	    cfi = &eliloConfigType;
+-      #elif __powerpc__
+-	    cfi = &yabootConfigType;
+-      #elif __sparc__
+-            cfi = &siloConfigType;
+-      #elif __s390__
+-            cfi = &ziplConfigType;
+-      #elif __s390x__
+-            cfi = &ziplConfigtype;
+-      #else
+-	    cfi = &grubConfigType;
+-      #endif
+-    }
++	if (!cfi) {
++		if (grub2FindConfig(&grub2ConfigType)) {
++			cfi = &grub2ConfigType;
++			if (envPath)
++				cfi->envFile = envPath;
++		} else
++#ifdef __ia64__
++			cfi = &eliloConfigType;
++#elif __powerpc__
++			cfi = &yabootConfigType;
++#elif __sparc__
++			cfi = &siloConfigType;
++#elif __s390__
++			cfi = &ziplConfigType;
++#elif __s390x__
++			cfi = &ziplConfigtype;
++#else
++			cfi = &grubConfigType;
++#endif
++	}
+ 
+-    if (!grubConfig) {
+-	if (cfi->findConfig)
+-	    grubConfig = cfi->findConfig(cfi);
+-	if (!grubConfig)
+-	    grubConfig = cfi->defaultConfig;
+-    }
++	if (!grubConfig) {
++		if (cfi->findConfig)
++			grubConfig = cfi->findConfig(cfi);
++		if (!grubConfig)
++			grubConfig = cfi->defaultConfig;
++	}
+ 
+-    if (bootloaderProbe && (displayDefault || kernelInfo ||
+-			    newKernelPath || removeKernelPath || makeDefault ||
+-			    defaultKernel || displayDefaultIndex || displayDefaultTitle ||
+-			    (defaultIndex >= 0))) {
+-	fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
++	if (bootloaderProbe && (displayDefault || kernelInfo ||
++				newKernelPath || removeKernelPath || makeDefault
++				|| defaultKernel || displayDefaultIndex
++				|| displayDefaultTitle
++				|| (defaultIndex >= 0))) {
++		fprintf(stderr,
++			_("grubby: --bootloader-probe may not be used with "
+ 			  "specified option"));
+-	return 1;
+-    }
+-
+-    if ((displayDefault || kernelInfo) && (newKernelPath ||
+-			   removeKernelPath)) {
+-	fprintf(stderr, _("grubby: --default-kernel and --info may not "
+-			  "be used when adding or removing kernels\n"));
+-	return 1;
+-    }
+-
+-    if (newKernelPath && !newKernelTitle) {
+-	fprintf(stderr, _("grubby: kernel title must be specified\n"));
+-	return 1;
+-    } else if (!newKernelPath && (copyDefault ||
+-				  (newKernelInitrd && !updateKernelPath)||
+-				  makeDefault || extraInitrdCount > 0)) {
+-	fprintf(stderr, _("grubby: kernel path expected\n"));
+-	return 1;
+-    }
+-
+-    if (newKernelPath && updateKernelPath) {
+-	fprintf(stderr, _("grubby: --add-kernel and --update-kernel may"
+-		          "not be used together"));
+-	return 1;
+-    }
+-
+-    if (makeDefault && defaultKernel) {
+-	fprintf(stderr, _("grubby: --make-default and --default-kernel "
+-			  "may not be used together\n"));
+-	return 1;
+-    } else if (defaultKernel && removeKernelPath &&
+-		!strcmp(defaultKernel, removeKernelPath)) {
+-	fprintf(stderr, _("grubby: cannot make removed kernel the default\n"));
+-	return 1;
+-    } else if (defaultKernel && newKernelPath &&
+-		!strcmp(defaultKernel, newKernelPath)) {
+-	makeDefault = 1;
+-	defaultKernel = NULL;
+-    }
+-    else if (defaultKernel && (defaultIndex >= 0)) {
+-	fprintf(stderr, _("grubby: --set-default and --set-default-index "
++		return 1;
++	}
++
++	if ((displayDefault || kernelInfo) && (newKernelPath ||
++					       removeKernelPath)) {
++		fprintf(stderr, _("grubby: --default-kernel and --info may not "
++				  "be used when adding or removing kernels\n"));
++		return 1;
++	}
++
++	if (newKernelPath && !newKernelTitle) {
++		fprintf(stderr, _("grubby: kernel title must be specified\n"));
++		return 1;
++	} else if (!newKernelPath && (copyDefault ||
++				      (newKernelInitrd && !updateKernelPath) ||
++				      makeDefault || extraInitrdCount > 0)) {
++		fprintf(stderr, _("grubby: kernel path expected\n"));
++		return 1;
++	}
++
++	if (newKernelPath && updateKernelPath) {
++		fprintf(stderr, _("grubby: --add-kernel and --update-kernel may"
++				  "not be used together"));
++		return 1;
++	}
++
++	if (makeDefault && defaultKernel) {
++		fprintf(stderr, _("grubby: --make-default and --default-kernel "
++				  "may not be used together\n"));
++		return 1;
++	} else if (defaultKernel && removeKernelPath &&
++		   !strcmp(defaultKernel, removeKernelPath)) {
++		fprintf(stderr,
++			_("grubby: cannot make removed kernel the default\n"));
++		return 1;
++	} else if (defaultKernel && newKernelPath &&
++		   !strcmp(defaultKernel, newKernelPath)) {
++		makeDefault = 1;
++		defaultKernel = NULL;
++	} else if (defaultKernel && (defaultIndex >= 0)) {
++		fprintf(stderr,
++			_("grubby: --set-default and --set-default-index "
+ 			  "may not be used together\n"));
+-	return 1;
+-    }
+-
+-    if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
+-	fprintf(stderr, _("grubby: output file must be specified if stdin "
+-			"is used\n"));
+-	return 1;
+-    }
+-
+-    if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
+-	&& !kernelInfo && !bootloaderProbe && !updateKernelPath
+-	&& !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
+-	&& (defaultIndex == -1)) {
+-	fprintf(stderr, _("grubby: no action specified\n"));
+-	return 1;
+-    }
+-
+-    flags |= badImageOkay ? GRUBBY_BADIMAGE_OKAY : 0;
+-
+-    if (cfi->needsBootPrefix) {
+-	if (!bootPrefix) {
+-	    bootPrefix = findBootPrefix();
+-	    if (!bootPrefix) return 1;
+-	} else {
+-	    /* this shouldn't end with a / */
+-	    if (bootPrefix[strlen(bootPrefix) - 1] == '/')
+-		bootPrefix[strlen(bootPrefix) - 1] = '\0';
++		return 1;
++	}
++
++	if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
++		fprintf(stderr,
++			_("grubby: output file must be specified if stdin "
++			  "is used\n"));
++		return 1;
++	}
++
++	if (!removeKernelPath && !newKernelPath && !displayDefault
++	    && !defaultKernel && !kernelInfo && !bootloaderProbe
++	    && !updateKernelPath && !removeMBKernel && !displayDefaultIndex
++	    && !displayDefaultTitle && (defaultIndex == -1)) {
++		fprintf(stderr, _("grubby: no action specified\n"));
++		return 1;
+ 	}
+-    } else {
+-	bootPrefix = "";
+-    }
+-
+-    if (!cfi->mbAllowExtraInitRds &&
+-	extraInitrdCount > 0) {
+-	fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
+-	return 1;
+-    }
+-
+-    if (bootloaderProbe) {
+-	int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
+-	struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
+-
+-	const char *grub2config = grub2FindConfig(&grub2ConfigType);
+-	if (grub2config) {
+-	    gconfig = readConfig(grub2config, &grub2ConfigType);
+-	    if (!gconfig)
+-		gr2c = 1;
+-	    else
+-		gr2c = checkForGrub2(gconfig);
+-	} 
+-
+-	const char *grubconfig = grubFindConfig(&grubConfigType);
+-	if (!access(grubconfig, F_OK)) {
+-	    gconfig = readConfig(grubconfig, &grubConfigType);
+-	    if (!gconfig)
+-		grc = 1;
+-	    else
+-		grc = checkForGrub(gconfig);
+-	} 
+-
+-	if (!access(liloConfigType.defaultConfig, F_OK)) {
+-	    lconfig = readConfig(liloConfigType.defaultConfig, &liloConfigType);
+-	    if (!lconfig)
+-		lrc = 1;
+-	    else
+-		lrc = checkForLilo(lconfig);
+-	} 
+-
+-	if (!access(eliloConfigType.defaultConfig, F_OK)) {
+-	    econfig = readConfig(eliloConfigType.defaultConfig,
+-				 &eliloConfigType);
+-	    if (!econfig)
+-		erc = 1;
+-	    else
+-		erc = checkForElilo(econfig);
++
++	flags |= badImageOkay ? GRUBBY_BADIMAGE_OKAY : 0;
++
++	if (cfi->needsBootPrefix) {
++		if (!bootPrefix) {
++			bootPrefix = findBootPrefix();
++			if (!bootPrefix)
++				return 1;
++		} else {
++			/* this shouldn't end with a / */
++			if (bootPrefix[strlen(bootPrefix) - 1] == '/')
++				bootPrefix[strlen(bootPrefix) - 1] = '\0';
++		}
++	} else {
++		bootPrefix = "";
+ 	}
+ 
+-	if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
+-	    lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
+-	    if (!lconfig)
+-		extrc = 1;
+-	    else
+-		extrc = checkForExtLinux(lconfig);
+-	} 
+-
+-
+-	if (!access(yabootConfigType.defaultConfig, F_OK)) {
+-	    yconfig = readConfig(yabootConfigType.defaultConfig,
+-				 &yabootConfigType);
+-	    if (!yconfig)
+-		yrc = 1;
+-	    else
+-		yrc = checkForYaboot(yconfig);
++	if (!cfi->mbAllowExtraInitRds && extraInitrdCount > 0) {
++		fprintf(stderr,
++			_("grubby: %s doesn't allow multiple initrds\n"),
++			cfi->defaultConfig);
++		return 1;
+ 	}
+ 
+-	if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
+-		erc == 1)
+-	    return 1;
+-
+-	if (lrc == 2) printf("lilo\n");
+-	if (gr2c == 2) printf("grub2\n");
+-	if (grc == 2) printf("grub\n");
+-	if (extrc == 2) printf("extlinux\n");
+-	if (yrc == 2) printf("yaboot\n");
+-	if (erc == 2) printf("elilo\n");
+-
+-	return 0;
+-    }
+-
+-    if (grubConfig == NULL) {
+-	printf("Could not find bootloader configuration file.\n");
+-	exit(1);
+-    }
+-
+-    config = readConfig(grubConfig, cfi);
+-    if (!config) return 1;
+-
+-    if (displayDefault) {
+-	struct singleLine * line;
+-	struct singleEntry * entry;
+-        char * rootspec;
+-
+-	if (config->defaultImage == -1) return 0;
+-	if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
+-		cfi->defaultIsSaved)
+-	    config->defaultImage = 0;
+-	entry = findEntryByIndex(config, config->defaultImage);
+-	if (!entry) return 0;
+-	if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
+-
+-	line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
+-	if (!line) return 0;
+-
+-        rootspec = getRootSpecifier(line->elements[1].item);
+-        printf("%s%s\n", bootPrefix, line->elements[1].item + 
+-               ((rootspec != NULL) ? strlen(rootspec) : 0));
+-
+-	return 0;
+-
+-    } else if (displayDefaultTitle) {
+-	struct singleLine * line;
+-	struct singleEntry * entry;
+-
+-	if (config->defaultImage == -1)
+-	    return 0;
+-	if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
+-		cfi->defaultIsSaved)
+-	    config->defaultImage = 0;
+-	entry = findEntryByIndex(config, config->defaultImage);
+-	if (!entry)
++	if (bootloaderProbe) {
++		int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
++		struct grubConfig *lconfig, *gconfig, *yconfig, *econfig;
++
++		const char *grub2config = grub2FindConfig(&grub2ConfigType);
++		if (grub2config) {
++			gconfig = readConfig(grub2config, &grub2ConfigType);
++			if (!gconfig)
++				gr2c = 1;
++			else
++				gr2c = checkForGrub2(gconfig);
++		}
++
++		const char *grubconfig = grubFindConfig(&grubConfigType);
++		if (!access(grubconfig, F_OK)) {
++			gconfig = readConfig(grubconfig, &grubConfigType);
++			if (!gconfig)
++				grc = 1;
++			else
++				grc = checkForGrub(gconfig);
++		}
++
++		if (!access(liloConfigType.defaultConfig, F_OK)) {
++			lconfig =
++			    readConfig(liloConfigType.defaultConfig,
++				       &liloConfigType);
++			if (!lconfig)
++				lrc = 1;
++			else
++				lrc = checkForLilo(lconfig);
++		}
++
++		if (!access(eliloConfigType.defaultConfig, F_OK)) {
++			econfig = readConfig(eliloConfigType.defaultConfig,
++					     &eliloConfigType);
++			if (!econfig)
++				erc = 1;
++			else
++				erc = checkForElilo(econfig);
++		}
++
++		if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
++			lconfig =
++			    readConfig(extlinuxConfigType.defaultConfig,
++				       &extlinuxConfigType);
++			if (!lconfig)
++				extrc = 1;
++			else
++				extrc = checkForExtLinux(lconfig);
++		}
++
++		if (!access(yabootConfigType.defaultConfig, F_OK)) {
++			yconfig = readConfig(yabootConfigType.defaultConfig,
++					     &yabootConfigType);
++			if (!yconfig)
++				yrc = 1;
++			else
++				yrc = checkForYaboot(yconfig);
++		}
++
++		if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1
++		    || erc == 1)
++			return 1;
++
++		if (lrc == 2)
++			printf("lilo\n");
++		if (gr2c == 2)
++			printf("grub2\n");
++		if (grc == 2)
++			printf("grub\n");
++		if (extrc == 2)
++			printf("extlinux\n");
++		if (yrc == 2)
++			printf("yaboot\n");
++		if (erc == 2)
++			printf("elilo\n");
++
+ 		return 0;
++	}
++
++	if (grubConfig == NULL) {
++		printf("Could not find bootloader configuration file.\n");
++		exit(1);
++	}
++
++	config = readConfig(grubConfig, cfi);
++	if (!config)
++		return 1;
++
++	if (displayDefault) {
++		struct singleLine *line;
++		struct singleEntry *entry;
++		char *rootspec;
++
++		if (config->defaultImage == -1)
++			return 0;
++		if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
++		    cfi->defaultIsSaved)
++			config->defaultImage = 0;
++		entry = findEntryByIndex(config, config->defaultImage);
++		if (!entry)
++			return 0;
++		if (!suitableImage(entry, bootPrefix, 0, flags))
++			return 0;
++
++		line =
++		    getLineByType(LT_KERNEL | LT_HYPER | LT_KERNEL_EFI |
++				  LT_KERNEL_16, entry->lines);
++		if (!line)
++			return 0;
++
++		rootspec = getRootSpecifier(line->elements[1].item);
++		printf("%s%s\n", bootPrefix, line->elements[1].item +
++		       ((rootspec != NULL) ? strlen(rootspec) : 0));
+ 
+-	if (!configureGrub2) {
+-	    char *title;
+-	    line = getLineByType(LT_TITLE, entry->lines);
+-	    if (!line)
+ 		return 0;
+-	    title = extractTitle(config, line);
+-	    if (!title)
++
++	} else if (displayDefaultTitle) {
++		struct singleLine *line;
++		struct singleEntry *entry;
++
++		if (config->defaultImage == -1)
++			return 0;
++		if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
++		    cfi->defaultIsSaved)
++			config->defaultImage = 0;
++		entry = findEntryByIndex(config, config->defaultImage);
++		if (!entry)
++			return 0;
++
++		if (!configureGrub2) {
++			char *title;
++			line = getLineByType(LT_TITLE, entry->lines);
++			if (!line)
++				return 0;
++			title = extractTitle(config, line);
++			if (!title)
++				return 0;
++			printf("%s\n", title);
++			free(title);
++		} else {
++			char *title;
++
++			dbgPrintf
++			    ("This is GRUB2, default title is embeded in menuentry\n");
++			line = getLineByType(LT_MENUENTRY, entry->lines);
++			if (!line)
++				return 0;
++			title = grub2ExtractTitle(line);
++			if (title)
++				printf("%s\n", title);
++		}
+ 		return 0;
+-	    printf("%s\n", title);
+-	    free(title);
+-	} else {
+-	    char * title;
+ 
+-	    dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
+-	    line = getLineByType(LT_MENUENTRY, entry->lines);
+-	    if (!line)
++	} else if (displayDefaultIndex) {
++		if (config->defaultImage == -1)
++			return 0;
++		if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
++		    cfi->defaultIsSaved)
++			config->defaultImage = 0;
++		printf("%i\n", config->defaultImage);
+ 		return 0;
+-	    title = grub2ExtractTitle(line);
+-	    if (title)
+-		printf("%s\n", title);
++
++	} else if (kernelInfo)
++		return displayInfo(config, kernelInfo, bootPrefix);
++
++	if (copyDefault) {
++		template = findTemplate(config, bootPrefix, NULL, 0, flags);
++		if (!template)
++			return 1;
+ 	}
+-	return 0;
+-
+-    } else if (displayDefaultIndex) {
+-        if (config->defaultImage == -1) return 0;
+-	if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
+-		cfi->defaultIsSaved)
+-	    config->defaultImage = 0;
+-        printf("%i\n", config->defaultImage);
+-        return 0;
+-
+-    } else if (kernelInfo)
+-	return displayInfo(config, kernelInfo, bootPrefix);
+-
+-    if (copyDefault) {
+-	template = findTemplate(config, bootPrefix, NULL, 0, flags);
+-	if (!template) return 1;
+-    }
+-
+-    markRemovedImage(config, removeKernelPath, bootPrefix);
+-    markRemovedImage(config, removeMBKernel, bootPrefix);
+-    setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault, 
+-		    bootPrefix, flags, defaultIndex);
+-    setFallbackImage(config, newKernelPath != NULL);
+-    if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
+-                    removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
+-    if (updateKernelPath && newKernelInitrd) {
+-	    if (newMBKernel) {
+-		    if (addMBInitrd(config, newMBKernel, updateKernelPath,
++
++	markRemovedImage(config, removeKernelPath, bootPrefix);
++	markRemovedImage(config, removeMBKernel, bootPrefix);
++	setDefaultImage(config, newKernelPath != NULL, defaultKernel,
++			makeDefault, bootPrefix, flags, defaultIndex);
++	setFallbackImage(config, newKernelPath != NULL);
++	if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
++			removeArgs, newMBKernelArgs, removeMBKernelArgs))
++		return 1;
++	if (updateKernelPath && newKernelInitrd) {
++		if (newMBKernel) {
++			if (addMBInitrd(config, newMBKernel, updateKernelPath,
+ 					bootPrefix, newKernelInitrd,
+ 					newKernelTitle))
+-			    return 1;
+-	    } else {
+-		    if (updateInitrd(config, updateKernelPath, bootPrefix,
+-					newKernelInitrd, newKernelTitle))
+-			return 1;
+-	    }
+-    }
+-    if (addNewKernel(config, template, bootPrefix, newKernelPath, 
+-                     newKernelTitle, newKernelArgs, newKernelInitrd, 
+-                     (const char **)extraInitrds, extraInitrdCount,
+-                     newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
+-    
++				return 1;
++		} else {
++			if (updateInitrd(config, updateKernelPath, bootPrefix,
++					 newKernelInitrd, newKernelTitle))
++				return 1;
++		}
++	}
++	if (addNewKernel(config, template, bootPrefix, newKernelPath,
++			 newKernelTitle, newKernelArgs, newKernelInitrd,
++			 (const char **)extraInitrds, extraInitrdCount,
++			 newMBKernel, newMBKernelArgs, newDevTreePath))
++		return 1;
+ 
+-    if (numEntries(config) == 0) {
+-        fprintf(stderr, _("grubby: doing this would leave no kernel entries. "
+-                          "Not writing out new config.\n"));
+-        return 1;
+-    }
++	if (numEntries(config) == 0) {
++		fprintf(stderr,
++			_("grubby: doing this would leave no kernel entries. "
++			  "Not writing out new config.\n"));
++		return 1;
++	}
+ 
+-    if (!outputFile)
+-	outputFile = (char *)grubConfig;
++	if (!outputFile)
++		outputFile = (char *)grubConfig;
+ 
+-    return writeConfig(config, outputFile, bootPrefix);
++	return writeConfig(config, outputFile, bootPrefix);
+ }
+-- 
+2.17.1
+
diff --git a/SOURCES/0015-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch b/SOURCES/0015-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch
new file mode 100644
index 0000000..a910c9c
--- /dev/null
+++ b/SOURCES/0015-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch
@@ -0,0 +1,586 @@
+From 5c8744420dfc891b2422db8f0be4bad2368f9970 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 6 Aug 2015 10:07:11 -0400
+Subject: [PATCH 15/55] Make SET_VARIABLE get handled individually in
+ GetNextLine()
+
+Resolves: rhbz#1152550
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c                 | 119 ++++++++++++++++++++++-----
+ .gitignore               |   2 +
+ test.sh                  |   8 ++
+ test/grub2.16            | 156 +++++++++++++++++++++++++++++++++++
+ test/results/add/g2-1.16 | 170 +++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 433 insertions(+), 22 deletions(-)
+ create mode 100644 test/grub2.16
+ create mode 100644 test/results/add/g2-1.16
+
+diff --git a/grubby.c b/grubby.c
+index fe6595b8386..d66c1c5a40a 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -75,6 +75,7 @@ struct lineElement {
+ };
+ 
+ enum lineType_e {
++	LT_UNIDENTIFIED = 0,
+ 	LT_WHITESPACE = 1 << 0,
+ 	LT_TITLE = 1 << 1,
+ 	LT_KERNEL = 1 << 2,
+@@ -747,6 +748,33 @@ static char *sdupprintf(const char *format, ...)
+ 	return buf;
+ }
+ 
++static inline int
++kwcmp(struct keywordTypes *kw, const char * label, int case_insensitive)
++{
++    int kwl = strlen(kw->key);
++    int ll = strlen(label);
++    int rc;
++    int (*snc)(const char *s1, const char *s2, size_t n) =
++           case_insensitive ? strncasecmp : strncmp;
++    int (*sc)(const char *s1, const char *s2) =
++           case_insensitive ? strcasecmp : strcmp;
++
++    rc = snc(kw->key, label, kwl);
++    if (rc)
++       return rc;
++
++    for (int i = kwl; i < ll; i++) {
++       if (isspace(label[i]))
++           return 0;
++       if (kw->separatorChar && label[i] == kw->separatorChar)
++           return 0;
++       else if (kw->nextChar && label[i] == kw->nextChar)
++           return 0;
++       return sc(kw->key+kwl, label+kwl);
++    }
++    return 0;
++}
++
+ static enum lineType_e preferredLineType(enum lineType_e type,
+ 					 struct configFileInfo *cfi)
+ {
+@@ -812,13 +840,8 @@ static enum lineType_e getTypeByKeyword(char *keyword,
+ 					struct configFileInfo *cfi)
+ {
+ 	for (struct keywordTypes * kw = cfi->keywords; kw->key; kw++) {
+-		if (cfi->caseInsensitive) {
+-			if (!strcasecmp(keyword, kw->key))
+-				return kw->type;
+-		} else {
+-			if (!strcmp(keyword, kw->key))
+-				return kw->type;
+-		}
++		if (!kwcmp(kw, keyword, cfi->caseInsensitive))
++			return kw->type;
+ 	}
+ 	return LT_UNKNOWN;
+ }
+@@ -913,6 +936,7 @@ static int readFile(int fd, char **bufPtr)
+ 
+ static void lineInit(struct singleLine *line)
+ {
++	line->type = LT_UNIDENTIFIED;
+ 	line->indent = NULL;
+ 	line->elements = NULL;
+ 	line->numElements = 0;
+@@ -995,7 +1019,7 @@ static int lineWrite(FILE * out, struct singleLine *line,
+ 
+ 		if (fprintf(out, "%s", line->elements[i].item) == -1)
+ 			return -1;
+-		if (i < line->numElements - 1)
++		if (i < line->numElements - 1 || line->type == LT_SET_VARIABLE)
+ 			if (fprintf(out, "%s", line->elements[i].indent) == -1)
+ 				return -1;
+ 	}
+@@ -1050,6 +1074,8 @@ static int getNextLine(char **bufPtr, struct singleLine *line,
+ 				break;
+ 			chptr++;
+ 		}
++		if (line->type == LT_UNIDENTIFIED)
++			line->type = getTypeByKeyword(start, cfi);
+ 		element->item = strndup(start, chptr - start);
+ 		start = chptr;
+ 
+@@ -1115,7 +1141,7 @@ static int getNextLine(char **bufPtr, struct singleLine *line,
+ 				line->type = LT_WHITESPACE;
+ 				line->numElements = 0;
+ 			}
+-		} else {
++		} else if (line->type == LT_INITRD) {
+ 			struct keywordTypes *kw;
+ 
+ 			kw = getKeywordByType(line->type, cfi);
+@@ -1177,6 +1203,39 @@ static int getNextLine(char **bufPtr, struct singleLine *line,
+ 					}
+ 				}
+ 			}
++		} else if (line->type == LT_SET_VARIABLE) {
++			/* and if it's a "set blah=" we need to split it
++			 * yet a third way to avoid rhbz# XXX FIXME :/
++			 */
++			char *eq;
++			int l;
++			int numElements = line->numElements;
++			struct lineElement *newElements;
++			eq = strchr(line->elements[1].item, '=');
++			if (!eq)
++				return 0;
++			l = eq - line->elements[1].item;
++			if (eq[1] != 0)
++				numElements++;
++			newElements = calloc(numElements,sizeof (*newElements));
++			memcpy(&newElements[0], &line->elements[0],
++			       sizeof (newElements[0]));
++			newElements[1].item =
++				strndup(line->elements[1].item, l);
++			newElements[1].indent = "=";
++			*(eq++) = '\0';
++			newElements[2].item = strdup(eq);
++			free(line->elements[1].item);
++			if (line->elements[1].indent)
++				newElements[2].indent = line->elements[1].indent;
++			for (int i = 2; i < line->numElements; i++) {
++				newElements[i+1].item = line->elements[i].item;
++				newElements[i+1].indent =
++					line->elements[i].indent;
++			}
++			free(line->elements);
++			line->elements = newElements;
++			line->numElements = numElements;
+ 		}
+ 	}
+ 
+@@ -1282,13 +1341,12 @@ static struct grubConfig *readConfig(const char *inName,
+ 			    getKeywordByType(LT_DEFAULT, cfi);
+ 			if (kwType && line->numElements == 3
+ 			    && !strcmp(line->elements[1].item, kwType->key)
+-			    && !is_special_grub2_variable(line->elements[2].
+-							  item)) {
++			    && !is_special_grub2_variable(
++						line->elements[2].item)) {
+ 				dbgPrintf("Line sets default config\n");
+ 				cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
+ 				defaultLine = line;
+ 			}
+-
+ 		} else if (iskernel(line->type)) {
+ 			/* if by some freak chance this is multiboot and the
+ 			 * "module" lines came earlier in the template, make
+@@ -1542,16 +1600,33 @@ static struct grubConfig *readConfig(const char *inName,
+ 				}
+ 			}
+ 		} else if (cfi->defaultIsVariable) {
+-			char *value = defaultLine->elements[2].item;
+-			while (*value && (*value == '"' || *value == '\'' ||
+-					  *value == ' ' || *value == '\t'))
+-				value++;
+-			cfg->defaultImage = strtol(value, &end, 10);
+-			while (*end && (*end == '"' || *end == '\'' ||
+-					*end == ' ' || *end == '\t'))
+-				end++;
+-			if (*end)
+-				cfg->defaultImage = -1;
++			if (defaultLine->numElements == 2) {
++				char *value = defaultLine->elements[1].item + 8;
++				while (*value && (*value == '"' ||
++						  *value == '\'' ||
++						  *value == ' ' ||
++						  *value == '\t'))
++					value++;
++				cfg->defaultImage = strtol(value, &end, 10);
++				while (*end && (*end == '"' || *end == '\'' ||
++						*end == ' ' || *end == '\t'))
++					end++;
++				if (*end)
++					cfg->defaultImage = -1;
++			} else if (defaultLine->numElements == 3) {
++				char *value = defaultLine->elements[2].item;
++				while (*value && (*value == '"' ||
++						  *value == '\'' ||
++						  *value == ' ' ||
++						  *value == '\t'))
++					value++;
++				cfg->defaultImage = strtol(value, &end, 10);
++				while (*end && (*end == '"' || *end == '\'' ||
++						*end == ' ' || *end == '\t'))
++					end++;
++				if (*end)
++					cfg->defaultImage = -1;
++			}
+ 		} else if (cfi->defaultSupportSaved &&
+ 			   !strncmp(defaultLine->elements[1].item, "saved",
+ 				    5)) {
+diff --git a/.gitignore b/.gitignore
+index e64d3bc0986..e78a392d601 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -1,3 +1,5 @@
+ grubby
+ version.h
+ *.o
++core.*
++vgcore.*
+diff --git a/test.sh b/test.sh
+index 2985fd62bf9..cd2d8707b5f 100755
+--- a/test.sh
++++ b/test.sh
+@@ -543,6 +543,14 @@ if [ "$testgrub2" == "y" ]; then
+         --copy-default --title "Fedora 21 Rescue" --args=root=/fooooo \
+         --remove-kernel=wtf --boot-filesystem=/boot/ --efi
+ 
++    # a grub2 add with a "set" of the form: set foo="bar=1,2".  bz#1152550
++    # has this being emitted as: set foo="bar=1,2"=1,2"
++    # which is wrong.
++    grub2Test grub2.16 add/g2-1.16 \
++        --add-kernel=/boot/vmlinuz-foo \
++        --copy-default --title 'Red Hat Enterprise Linux Server' \
++        --args=root=/dev/mapper/foo--
++
+     testing="GRUB2 add initrd"
+     grub2Test grub2.2 add/g2-1.4 --update-kernel=/boot/new-kernel.img \
+         --initrd=/boot/new-initrd --boot-filesystem=/boot/
+diff --git a/test/grub2.16 b/test/grub2.16
+new file mode 100644
+index 00000000000..136880a61ee
+--- /dev/null
++++ b/test/grub2.16
+@@ -0,0 +1,156 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++serial --speed=115200
++terminal_input serial console
++terminal_output serial console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=5
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=5
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/00_tuned ###
++set tuned_params="isolcpus=1,3"
++### END /etc/grub.d/00_tuned ###
++
++### BEGIN /etc/grub.d/01_users ###
++if [ -f ${prefix}/user.cfg ]; then
++  source ${prefix}/user.cfg
++  if [ -n ${GRUB2_PASSWORD} ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root ${GRUB2_PASSWORD}
++  fi
++fi
++### END /etc/grub.d/01_users ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  cae02b39-f239-4d26-9032-674d261c93d8
++	else
++	  search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8
++	fi
++	linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81  $tuned_params LANG=en_US.UTF-8
++}
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  cae02b39-f239-4d26-9032-674d261c93d8
++	else
++	  search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8
++	fi
++	linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81  $tuned_params
++	initrd16 /initramfs-3.10.0-296.el7.x86_64.img
++}
++menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  cae02b39-f239-4d26-9032-674d261c93d8
++	else
++	  search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8
++	fi
++	linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81  $tuned_params
++	initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img
++}
++if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi;
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.16 b/test/results/add/g2-1.16
+new file mode 100644
+index 00000000000..fc98757f4fc
+--- /dev/null
++++ b/test/results/add/g2-1.16
+@@ -0,0 +1,170 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++serial --speed=115200
++terminal_input serial console
++terminal_output serial console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=5
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=5
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/00_tuned ###
++set tuned_params="isolcpus=1,3"
++### END /etc/grub.d/00_tuned ###
++
++### BEGIN /etc/grub.d/01_users ###
++if [ -f ${prefix}/user.cfg ]; then
++  source ${prefix}/user.cfg
++  if [ -n ${GRUB2_PASSWORD} ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root ${GRUB2_PASSWORD}
++  fi
++fi
++### END /etc/grub.d/01_users ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Red Hat Enterprise Linux Server' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  cae02b39-f239-4d26-9032-674d261c93d8
++	else
++	  search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8
++	fi
++	linux16 /vmlinuz-foo root=/dev/mapper/foo-- ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81  $tuned_params LANG=en_US.UTF-8
++}
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-297.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  cae02b39-f239-4d26-9032-674d261c93d8
++	else
++	  search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8
++	fi
++	linux16 /vmlinuz-3.10.0-297.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81  $tuned_params LANG=en_US.UTF-8
++}
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-296.el7.x86_64-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  cae02b39-f239-4d26-9032-674d261c93d8
++	else
++	  search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8
++	fi
++	linux16 /vmlinuz-3.10.0-296.el7.x86_64 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81  $tuned_params
++	initrd16 /initramfs-3.10.0-296.el7.x86_64.img
++}
++menuentry 'Red Hat Enterprise Linux Server (0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7-advanced-ae7b3742-9092-4432-9f7f-8abdbf0dc3db' {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  cae02b39-f239-4d26-9032-674d261c93d8
++	else
++	  search --no-floppy --fs-uuid --set=root cae02b39-f239-4d26-9032-674d261c93d8
++	fi
++	linux16 /vmlinuz-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7 root=/dev/mapper/rhel_hp--dl380pgen8--02--vm--10-root ro crashkernel=auto rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/root rd.lvm.lv=rhel_hp-dl380pgen8-02-vm-10/swap console=ttyS0,115200n81  $tuned_params
++	initrd16 /initramfs-0-rescue-cc21b92886f9ebbd3ed5a494639b7fd7.img
++}
++if [ "x$default" = 'Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)' ]; then default='Advanced options for Red Hat Enterprise Linux Server>Red Hat Enterprise Linux Server (3.10.0-296.el7.x86_64) 7.2 (Maipo)'; fi;
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+-- 
+2.17.1
+
diff --git a/SOURCES/0016-Specify-bootloader-directory-in-the-test-case-for-11.patch b/SOURCES/0016-Specify-bootloader-directory-in-the-test-case-for-11.patch
new file mode 100644
index 0000000..a4449ee
--- /dev/null
+++ b/SOURCES/0016-Specify-bootloader-directory-in-the-test-case-for-11.patch
@@ -0,0 +1,31 @@
+From c014354834f496ade11dda3f6406cbddbee25f75 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 1 Sep 2015 11:02:07 -0400
+Subject: [PATCH 16/55] Specify bootloader directory in the test case for
+ 1152550.
+
+Because otherwise it blows up when built in mock without /boot mounted.
+
+Related: rhbz#1152550
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ test.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/test.sh b/test.sh
+index cd2d8707b5f..ba466a50501 100755
+--- a/test.sh
++++ b/test.sh
+@@ -547,7 +547,7 @@ if [ "$testgrub2" == "y" ]; then
+     # has this being emitted as: set foo="bar=1,2"=1,2"
+     # which is wrong.
+     grub2Test grub2.16 add/g2-1.16 \
+-        --add-kernel=/boot/vmlinuz-foo \
++        --boot-filesystem=/boot --add-kernel=/boot/vmlinuz-foo \
+         --copy-default --title 'Red Hat Enterprise Linux Server' \
+         --args=root=/dev/mapper/foo--
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0017-Fix-dracut-cmdline-options-and-conditionalize-them-t.patch b/SOURCES/0017-Fix-dracut-cmdline-options-and-conditionalize-them-t.patch
new file mode 100644
index 0000000..3c211b6
--- /dev/null
+++ b/SOURCES/0017-Fix-dracut-cmdline-options-and-conditionalize-them-t.patch
@@ -0,0 +1,63 @@
+From a8fd0f15979d5f4632c337c8bcfbdbae2b957f67 Mon Sep 17 00:00:00 2001
+From: marcosfrm <marcosfrm@users.noreply.github.com>
+Date: Tue, 6 Oct 2015 08:29:02 -0300
+Subject: [PATCH 17/55] Fix dracut cmdline options and conditionalize them to
+ --add-dracut-args
+
+By default initramfs generated by dracut is HostOnly and has vconsole.conf and locale.conf included. Instead of killing this import section, conditionalize it to --add-dracut-args.
+
+Reference: http://git.kernel.org/cgit/boot/dracut/dracut.git/tree/modules.d/10i18n/parse-i18n.sh
+---
+ new-kernel-pkg | 35 ++++++++++++++---------------------
+ 1 file changed, 14 insertions(+), 21 deletions(-)
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index 90652da06b7..997fb1f4987 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -825,28 +825,21 @@ if [[ ${ARCH} =~ armv[5|7].*l ]]; then
+ fi
+ [ -n "$verbose" ] && echo "devtreedir is $devtreedir"
+ 
+-# add dracut i18n, keyboard and plymouth kernel args if requested
+-if [ -n "$dracut" -o -n "$adddracutargs" ]; then
+-    if [ -r /etc/vconsole.conf ]; then
+-	. /etc/vconsole.conf
+-    elif  [ -r /etc/sysconfig/keyboard ]; then
+-	. /etc/sysconfig/keyboard
+-    fi
++# add dracut kernel args if requested
++if [ -n "$dracut" -a -n "$adddracutargs" ]; then
++    [ -r /etc/vconsole.conf ] && . /etc/vconsole.conf
++    [ -r /etc/locale.conf ] && . /etc/locale.conf
+ 
+-    if [ -r /etc/locale.conf ]; then
+-	. /etc/locale.conf
+-    elif [ -r /etc/sysconfig/i18n ]; then
+-	. /etc/sysconfig/i18n
+-    fi
+-
+-    for i in SYSFONT SYSFONTACM UNIMAP LANG KEYTABLE; do
+-        val=$(eval echo \$$i)
+-        [ -n "$val" ] && kernargs="$kernargs $i=$val"
+-    done
+-
+-    if [ -n "$KEYBOARDTYPE" -a "$KEYBOARDTYPE" != "pc" ]; then
+-         kernargs="$kernargs KEYBOARDTYPE=$KEYBOARDTYPE"
+-    fi
++    while read opt rd_opt; do
++        [ -n "${!opt}" ] && kernargs="$kernargs $rd_opt=\"${!opt}\""
++    done <<< 'KEYMAP      rd.vconsole.keymap
++              FONT        rd.vconsole.font
++              FONT_MAP    rd.vconsole.font.map
++              FONT_UNIMAP rd.vconsole.font.unimap
++              UNICODE     rd.vconsole.font.unicode
++              EXT_KEYMAP  rd.vconsole.keymap.ext
++              LANG        rd.locale.LANG
++              LC_ALL      rd.locale.LC_ALL'
+ fi
+ 
+ # set this as the default if we have the package and it matches
+-- 
+2.17.1
+
diff --git a/SOURCES/0018-Add-missing-space.patch b/SOURCES/0018-Add-missing-space.patch
new file mode 100644
index 0000000..81b2252
--- /dev/null
+++ b/SOURCES/0018-Add-missing-space.patch
@@ -0,0 +1,25 @@
+From 7ee039e026fe02e01dd4c7fd2b18682b8737697c Mon Sep 17 00:00:00 2001
+From: marcosfrm <marcosfrm@users.noreply.github.com>
+Date: Tue, 6 Oct 2015 08:40:44 -0300
+Subject: [PATCH 18/55] Add missing space
+
+---
+ new-kernel-pkg | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index 997fb1f4987..9f56c470b4a 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -925,7 +925,7 @@ fi
+ # to by-pass writeback delay.
+ # PPC64LE-only to deal with Petitboot issues
+ if [ "$ARCH" = "ppc64le" ]; then
+-    sync && mountpoint -q /boot &&fsfreeze -f /boot && fsfreeze -u /boot
++    sync && mountpoint -q /boot && fsfreeze -f /boot && fsfreeze -u /boot
+ fi
+ 
+ exit 0
+-- 
+2.17.1
+
diff --git a/SOURCES/0019-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch b/SOURCES/0019-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch
new file mode 100644
index 0000000..bdb6621
--- /dev/null
+++ b/SOURCES/0019-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch
@@ -0,0 +1,123 @@
+From ae22f8322d2f2dccd19003fccd390fe19f7126c1 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 26 Oct 2015 14:22:39 -0400
+Subject: [PATCH 19/55] Always do the "rungrubby --debug" after the normal
+ kernel on install.
+
+This way the during an update, the right kernel is picked as "default"
+for the command line arguments.
+
+Related: rhbz#1212128
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ new-kernel-pkg | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index 9f56c470b4a..9574dbbf10b 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -243,8 +243,8 @@ install() {
+ 		--args=\"root=$rootdevice $kernargs \$debugargs\" \
+ 		--remove-kernel=\"TITLE=$title\$debugtitle\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS} $makedefault
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby for grub 0.97"
+     fi
+@@ -257,8 +257,8 @@ install() {
+ 		${mbargs:+--mbargs=\"$mbargs\"} \
+ 		--args=\"root=$rootdevice $kernargs \$debugargs\" \
+ 		--remove-kernel=\"TITLE=$title\$debugtitle\""
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS} $makedefault
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby for grub 2"
+     fi
+@@ -272,8 +272,8 @@ install() {
+ 		${mbargs:+--mbargs=\"$mbargs\"} \
+ 		--args=\"root=$rootdevice $kernargs \$debugargs\" \
+ 		--remove-kernel=\"TITLE=$title\$debugtitle\""
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS} $makedefault
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby for grub 2 with UEFI"
+     fi
+@@ -288,8 +288,8 @@ install() {
+ 		--args=\"root=$rootdevice $kernargs \$debugargs\" \
+ 		--remove-kernel=\"TITLE=$version\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS} $makedefault
++	rungrubby --debug ${ARGS}
+ 	if [ -n "$runLilo" ]; then
+ 	    [ -n "$verbose" ] && echo "running $lilo"
+ 	    if [ ! -x $lilo ] ; then
+@@ -313,8 +313,8 @@ install() {
+ 	    --args=\"root=$rootdevice $kernargs \$debugargs\" \
+ 	    --remove-kernel=\"TITLE=$title\$debugtitle\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS} $makedefault
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby for extlinux"
+     fi
+@@ -480,8 +480,8 @@ update() {
+ 		${mbkernel:+--add-multiboot=\"$mbkernel\"} \
+ 		--title=\"$title\$debugtitle\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS}
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby"
+     fi
+@@ -493,8 +493,8 @@ update() {
+ 		${removeargs:+--remove-args=\"$removeargs\"} \
+ 		--title=\"$title\$debugtitle\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS}
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby"
+     fi
+@@ -506,8 +506,8 @@ update() {
+ 		${removeargs:+--remove-args=\"$removeargs\"} \
+ 		--title=\"$title\$debugtitle\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS}
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby"
+     fi
+@@ -519,8 +519,8 @@ update() {
+ 		${removeargs:+--remove-args=\"$removeargs\"} \
+ 		--title=\"$title\$debugtitle\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS}
++	rungrubby --debug ${ARGS}
+ 
+ 	if [ -n "$runLilo" ]; then
+ 	    [ -n "$verbose" ] && echo "running $lilo"
+@@ -571,8 +571,8 @@ update() {
+ 		${removeargs:+--remove-args=\"$removeargs\"} \
+ 		--title=\"$title\$debugtitle\""
+ 
+-	rungrubby --debug ${ARGS}
+ 	rungrubby ${ARGS}
++	rungrubby --debug ${ARGS}
+     else
+ 	[ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby"
+     fi
+-- 
+2.17.1
+
diff --git a/SOURCES/0020-grubby-add-set-index-to-specify-which-position-to-ad.patch b/SOURCES/0020-grubby-add-set-index-to-specify-which-position-to-ad.patch
new file mode 100644
index 0000000..7270837
--- /dev/null
+++ b/SOURCES/0020-grubby-add-set-index-to-specify-which-position-to-ad.patch
@@ -0,0 +1,298 @@
+From 8efba98644f9262d74a42fac7ea39d197192443a Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 22 Jun 2016 14:07:49 -0400
+Subject: [PATCH 20/55] grubby: add --set-index to specify which position to
+ add new entries as
+
+This adds an option, "--set-index N", to grubby, and will cause creation
+of any new entry to be at a particular zero-indexed position in the
+resulting configuration file.
+
+Related: rhbz#1285601
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c               | 26 +++++++++++++++++++++-----
+ .gitignore             |  1 +
+ grubby.8               |  8 ++++++--
+ test.sh                | 14 ++++++++++++++
+ test/grub.15           | 19 +++++++++++++++++++
+ test/results/add/g1.10 | 22 ++++++++++++++++++++++
+ test/results/add/g1.17 | 19 +++++++++++++++++++
+ test/results/add/g1.8  | 22 ++++++++++++++++++++++
+ test/results/add/g1.9  | 22 ++++++++++++++++++++++
+ 9 files changed, 146 insertions(+), 7 deletions(-)
+ create mode 100644 test/grub.15
+ create mode 100644 test/results/add/g1.10
+ create mode 100644 test/results/add/g1.17
+ create mode 100644 test/results/add/g1.8
+ create mode 100644 test/results/add/g1.9
+
+diff --git a/grubby.c b/grubby.c
+index d66c1c5a40a..54625e7da0a 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -4207,9 +4207,9 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template,
+ 		 const char *newKernelArgs, const char *newKernelInitrd,
+ 		 const char **extraInitrds, int extraInitrdCount,
+ 		 const char *newMBKernel, const char *newMBKernelArgs,
+-		 const char *newDevTreePath)
++		 const char *newDevTreePath, int newIndex)
+ {
+-	struct singleEntry *new;
++	struct singleEntry *new, *entry, *prev = NULL;
+ 	struct singleLine *newLine = NULL, *tmplLine = NULL, *masterLine = NULL;
+ 	int needs;
+ 	char *chptr;
+@@ -4239,9 +4239,20 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template,
+ 	new = malloc(sizeof(*new));
+ 	new->skip = 0;
+ 	new->multiboot = 0;
+-	new->next = config->entries;
+ 	new->lines = NULL;
+-	config->entries = new;
++	entry = config->entries;
++	for (unsigned int i = 0; i < newIndex; i++) {
++		if (!entry)
++			break;
++		prev = entry;
++		entry = entry->next;
++	}
++	new->next = entry;
++
++	if (prev)
++		prev->next = new;
++	else
++		config->entries = new;
+ 
+ 	/* copy/update from the template */
+ 	needs = NEED_KERNEL | NEED_TITLE;
+@@ -4734,6 +4745,7 @@ int main(int argc, const char **argv)
+ 	char *newDevTreePath = NULL;
+ 	char *newMBKernel = NULL;
+ 	char *newMBKernelArgs = NULL;
++	int newIndex = 0;
+ 	char *removeMBKernelArgs = NULL;
+ 	char *removeMBKernel = NULL;
+ 	char *bootPrefix = NULL;
+@@ -4840,6 +4852,9 @@ int main(int argc, const char **argv)
+ 		{"set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
+ 		 _("make the given entry index the default entry"),
+ 		 _("entry-index")},
++		{"set-index", 0, POPT_ARG_INT, &newIndex, 0,
++		 _("use the given index when creating a new entry"),
++		 _("entry-index")},
+ 		{"silo", 0, POPT_ARG_NONE, &configureSilo, 0,
+ 		 _("configure silo bootloader")},
+ 		{"title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
+@@ -5255,7 +5270,8 @@ int main(int argc, const char **argv)
+ 	if (addNewKernel(config, template, bootPrefix, newKernelPath,
+ 			 newKernelTitle, newKernelArgs, newKernelInitrd,
+ 			 (const char **)extraInitrds, extraInitrdCount,
+-			 newMBKernel, newMBKernelArgs, newDevTreePath))
++			 newMBKernel, newMBKernelArgs, newDevTreePath,
++			 newIndex))
+ 		return 1;
+ 
+ 	if (numEntries(config) == 0) {
+diff --git a/.gitignore b/.gitignore
+index e78a392d601..1c00ff7c5ed 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -3,3 +3,4 @@ version.h
+ *.o
+ core.*
+ vgcore.*
++*.tar.*
+diff --git a/grubby.8 b/grubby.8
+index 355b6eb6908..a4691f8ddb2 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -7,12 +7,12 @@ grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl
+        [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR] 
+        [--bootloader-probe] [--config-file \fIpath\fR] [--copy-default]
+        [--debug] [--default-kernel] [--default-index] [--default-title]
+-       [--devtree=\fIdevicetree.dtb\fR]
++       [--devtree=\fIdevicetree.dtb\fR] [--set-entry=\fIentry-index\fR]
+        [--grub] [--lilo] [--yaboot] [--silo] [--zipl]
+        [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR] 
+        [--make-default] [-o path] [--version]
+        [--remove-kernel=\fIkernel-path\fR] [--remove-args=\fIargs\fR]
+-       [--set-default=\fIkernel-path\fR] [--set-default-index=\fientry-index\fR]
++       [--set-default=\fIkernel-path\fR] [--set-default-index=\fIentry-index\fR]
+        [--title=entry-title] [--add-multiboot=\fImultiboot-path\fR]
+        [--mbargs=\fIargs\fR] [--remove-multiboot=\fImultiboot-path\fR]
+        [--remove-mbargs=\fIargs\fR]
+@@ -48,6 +48,10 @@ with that title are used.
+ \fB-\-add-kernel\fR=\fIkernel-path\fR
+ Add a new boot entry for the kernel located at \fIkernel-path\fR.
+ 
++.TP
++\fB-\-set-entry\fR=\fIentry-index\fR
++Set the position at which to add a new entry created with \fB-\-add-kernel\fR.
++
+ .TP
+ \fB-\-args\fR=\fIkernel-args\fR
+ When a new kernel is added, this specifies the command line arguments
+diff --git a/test.sh b/test.sh
+index ba466a50501..7d1794c83df 100755
+--- a/test.sh
++++ b/test.sh
+@@ -485,6 +485,20 @@ grubTest grub.8 add/g8.2 --add-kernel=/boot/new-kernel.img --title='title' \
+ grubTest grub.11 add/g11.1 --add-kernel=/boot/new-kernel.img --title='title' \
+     --initrd=/boot/new-initrd --boot-filesystem=/boot --copy-default \
+     --args='console=tty0 console=ttyS1,9600n81 single'
++grubTest grub.1 add/g1.1 --add-kernel=/boot/new-kernel.img --title='title' \
++    --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 0
++grubTest grub.1 add/g1.17 --add-kernel=/boot/new-kernel.img --title='title' \
++    --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 1
++grubTest grub.1 add/g1.17 --add-kernel=/boot/new-kernel.img --title='title' \
++    --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 2
++grubTest grub.15 add/g1.10 --add-kernel=/boot/new-kernel.img --title='title' \
++    --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 0
++grubTest grub.15 add/g1.8 --add-kernel=/boot/new-kernel.img --title='title' \
++    --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 1
++grubTest grub.15 add/g1.9 --add-kernel=/boot/new-kernel.img --title='title' \
++    --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 2
++grubTest grub.15 add/g1.9 --add-kernel=/boot/new-kernel.img --title='title' \
++    --initrd=/boot/new-initrd --boot-filesystem=/ --set-index 5
+ 
+ testgrub2=n
+ ARCH=$(uname -m | sed s,i[3456789]86,ia32,)
+diff --git a/test/grub.15 b/test/grub.15
+new file mode 100644
+index 00000000000..e1c5f8a9b52
+--- /dev/null
++++ b/test/grub.15
+@@ -0,0 +1,19 @@
++# grub.conf generated by anaconda
++#
++# Note that you do not have to rerun grub after making changes to this file
++# NOTICE:  You have a /boot partition.  This means that
++#          all kernel and initrd paths are relative to /boot/, eg.
++#          root (hd0,0)
++#          kernel /vmlinuz-version ro root=/dev/sda1
++#          initrd /initrd-version.img
++#boot=/dev/hda
++default=1
++timeout=10
++splashimage=(hd0,0)/grub/splash.xpm.gz
++title Red Hat Linux (2.4.7-2)
++	root (hd0,0)
++	kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1
++	initrd /initrd-2.4.7-2.img
++title zonk
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
+diff --git a/test/results/add/g1.10 b/test/results/add/g1.10
+new file mode 100644
+index 00000000000..dcdd8a8ce10
+--- /dev/null
++++ b/test/results/add/g1.10
+@@ -0,0 +1,22 @@
++# grub.conf generated by anaconda
++#
++# Note that you do not have to rerun grub after making changes to this file
++# NOTICE:  You have a /boot partition.  This means that
++#          all kernel and initrd paths are relative to /boot/, eg.
++#          root (hd0,0)
++#          kernel /vmlinuz-version ro root=/dev/sda1
++#          initrd /initrd-version.img
++#boot=/dev/hda
++default=2
++timeout=10
++splashimage=(hd0,0)/grub/splash.xpm.gz
++title title
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
++title Red Hat Linux (2.4.7-2)
++	root (hd0,0)
++	kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1
++	initrd /initrd-2.4.7-2.img
++title zonk
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
+diff --git a/test/results/add/g1.17 b/test/results/add/g1.17
+new file mode 100644
+index 00000000000..6a388228768
+--- /dev/null
++++ b/test/results/add/g1.17
+@@ -0,0 +1,19 @@
++# grub.conf generated by anaconda
++#
++# Note that you do not have to rerun grub after making changes to this file
++# NOTICE:  You have a /boot partition.  This means that
++#          all kernel and initrd paths are relative to /boot/, eg.
++#          root (hd0,0)
++#          kernel /vmlinuz-version ro root=/dev/sda1
++#          initrd /initrd-version.img
++#boot=/dev/hda
++default=1
++timeout=10
++splashimage=(hd0,0)/grub/splash.xpm.gz
++title Red Hat Linux (2.4.7-2)
++	root (hd0,0)
++	kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1
++	initrd /initrd-2.4.7-2.img
++title title
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
+diff --git a/test/results/add/g1.8 b/test/results/add/g1.8
+new file mode 100644
+index 00000000000..5893a2f5af1
+--- /dev/null
++++ b/test/results/add/g1.8
+@@ -0,0 +1,22 @@
++# grub.conf generated by anaconda
++#
++# Note that you do not have to rerun grub after making changes to this file
++# NOTICE:  You have a /boot partition.  This means that
++#          all kernel and initrd paths are relative to /boot/, eg.
++#          root (hd0,0)
++#          kernel /vmlinuz-version ro root=/dev/sda1
++#          initrd /initrd-version.img
++#boot=/dev/hda
++default=2
++timeout=10
++splashimage=(hd0,0)/grub/splash.xpm.gz
++title Red Hat Linux (2.4.7-2)
++	root (hd0,0)
++	kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1
++	initrd /initrd-2.4.7-2.img
++title title
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
++title zonk
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
+diff --git a/test/results/add/g1.9 b/test/results/add/g1.9
+new file mode 100644
+index 00000000000..310623d13d2
+--- /dev/null
++++ b/test/results/add/g1.9
+@@ -0,0 +1,22 @@
++# grub.conf generated by anaconda
++#
++# Note that you do not have to rerun grub after making changes to this file
++# NOTICE:  You have a /boot partition.  This means that
++#          all kernel and initrd paths are relative to /boot/, eg.
++#          root (hd0,0)
++#          kernel /vmlinuz-version ro root=/dev/sda1
++#          initrd /initrd-version.img
++#boot=/dev/hda
++default=2
++timeout=10
++splashimage=(hd0,0)/grub/splash.xpm.gz
++title Red Hat Linux (2.4.7-2)
++	root (hd0,0)
++	kernel /vmlinuz-2.4.7-2 ro root=/dev/sda1
++	initrd /initrd-2.4.7-2.img
++title zonk
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
++title title
++	kernel /boot/new-kernel.img
++	initrd /boot/new-initrd
+-- 
+2.17.1
+
diff --git a/SOURCES/0021-Fix-thinko-on-set-index-naming.patch b/SOURCES/0021-Fix-thinko-on-set-index-naming.patch
new file mode 100644
index 0000000..bade5f6
--- /dev/null
+++ b/SOURCES/0021-Fix-thinko-on-set-index-naming.patch
@@ -0,0 +1,37 @@
+From 0a4d6c3ae61bd6fd6a664b2b55b3e9453cf813ac Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 23 Jun 2016 14:47:35 -0400
+Subject: [PATCH 21/55] Fix thinko on --set-index naming.
+
+Related: rhbz#1285601
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.8 | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grubby.8 b/grubby.8
+index a4691f8ddb2..f1bfb9336e9 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -7,7 +7,7 @@ grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl
+        [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR] 
+        [--bootloader-probe] [--config-file \fIpath\fR] [--copy-default]
+        [--debug] [--default-kernel] [--default-index] [--default-title]
+-       [--devtree=\fIdevicetree.dtb\fR] [--set-entry=\fIentry-index\fR]
++       [--devtree=\fIdevicetree.dtb\fR] [--set-index=\fIentry-index\fR]
+        [--grub] [--lilo] [--yaboot] [--silo] [--zipl]
+        [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR] 
+        [--make-default] [-o path] [--version]
+@@ -49,7 +49,7 @@ with that title are used.
+ Add a new boot entry for the kernel located at \fIkernel-path\fR.
+ 
+ .TP
+-\fB-\-set-entry\fR=\fIentry-index\fR
++\fB-\-set-index\fR=\fIentry-index\fR
+ Set the position at which to add a new entry created with \fB-\-add-kernel\fR.
+ 
+ .TP
+-- 
+2.17.1
+
diff --git a/SOURCES/0022-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch b/SOURCES/0022-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch
new file mode 100644
index 0000000..5ffc0d6
--- /dev/null
+++ b/SOURCES/0022-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch
@@ -0,0 +1,386 @@
+From a23da4b29281ca07b06aab0bb772fedfe1f8ce35 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 24 Jun 2016 16:13:41 -0400
+Subject: [PATCH 22/55] Add a test case for a failure rmarshall saw in
+ --set-index=
+
+Related: rhbz#1285601
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ test.sh                            |   9 ++
+ test/grub2-support_files/grubenv.3 |   3 +
+ test/grub2.18                      | 154 ++++++++++++++++++++++++++
+ test/results/add/g2-1.18           | 168 +++++++++++++++++++++++++++++
+ 4 files changed, 334 insertions(+)
+ create mode 100644 test/grub2-support_files/grubenv.3
+ create mode 100644 test/grub2.18
+ create mode 100644 test/results/add/g2-1.18
+
+diff --git a/test.sh b/test.sh
+index 7d1794c83df..fb7cd2381d5 100755
+--- a/test.sh
++++ b/test.sh
+@@ -565,6 +565,15 @@ if [ "$testgrub2" == "y" ]; then
+         --copy-default --title 'Red Hat Enterprise Linux Server' \
+         --args=root=/dev/mapper/foo--
+ 
++    # copy a stanza and add arguments as well, while using --set-index=
++    testing="GRUB2 add stanza and new args with --set-index="
++    grub2Test grub2.18 add/g2-1.18  --env grubenv.3 \
++        --add-kernel=/boot/vmlinuz-3.10.0-327.22.2.el7.x86_64.debug \
++        --boot-filesystem=/boot --copy-default \
++        --title "Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo) with debugging" \
++        --args="root=/dev/mapper/rhel_team--area--222-root systemd.log_level=debug systemd.log_target=kmsg" \
++        --set-index=1
++
+     testing="GRUB2 add initrd"
+     grub2Test grub2.2 add/g2-1.4 --update-kernel=/boot/new-kernel.img \
+         --initrd=/boot/new-initrd --boot-filesystem=/boot/
+diff --git a/test/grub2-support_files/grubenv.3 b/test/grub2-support_files/grubenv.3
+new file mode 100644
+index 00000000000..b9a8c798328
+--- /dev/null
++++ b/test/grub2-support_files/grubenv.3
+@@ -0,0 +1,3 @@
++# GRUB Environment Block
++saved_entry=Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo) with debugging
++#############################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################
+\ No newline at end of file
+diff --git a/test/grub2.18 b/test/grub2.18
+new file mode 100644
+index 00000000000..529608da773
+--- /dev/null
++++ b/test/grub2.18
+@@ -0,0 +1,154 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=5
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=5
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/00_tuned ###
++set tuned_params=""
++### END /etc/grub.d/00_tuned ###
++
++### BEGIN /etc/grub.d/01_users ###
++if [ -f ${prefix}/user.cfg ]; then
++  source ${prefix}/user.cfg
++  if [ -n ${GRUB2_PASSWORD} ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root ${GRUB2_PASSWORD}
++  fi
++fi
++### END /etc/grub.d/01_users ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	else
++	  search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	fi
++	linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64.debug root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8
++}
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	else
++	  search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	fi
++	linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8
++	initrd16 /initramfs-3.10.0-327.el7.x86_64.img
++}
++menuentry 'Red Hat Enterprise Linux Server (0-rescue-925cd320373b6a4a9a66a26371afccd2) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-925cd320373b6a4a9a66a26371afccd2-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	else
++	  search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	fi
++	linux16 /vmlinuz-0-rescue-925cd320373b6a4a9a66a26371afccd2 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet
++	initrd16 /initramfs-0-rescue-925cd320373b6a4a9a66a26371afccd2.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.18 b/test/results/add/g2-1.18
+new file mode 100644
+index 00000000000..ca5fe2393d5
+--- /dev/null
++++ b/test/results/add/g2-1.18
+@@ -0,0 +1,168 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=5
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=5
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/00_tuned ###
++set tuned_params=""
++### END /etc/grub.d/00_tuned ###
++
++### BEGIN /etc/grub.d/01_users ###
++if [ -f ${prefix}/user.cfg ]; then
++  source ${prefix}/user.cfg
++  if [ -n ${GRUB2_PASSWORD} ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root ${GRUB2_PASSWORD}
++  fi
++fi
++### END /etc/grub.d/01_users ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	else
++	  search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	fi
++	linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64.debug root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8
++}
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.22.2.el7.x86_64.debug) 7.2 (Maipo) with debugging' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	else
++	  search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	fi
++	linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64.debug root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8 systemd.log_level=debug systemd.log_target=kmsg
++}
++menuentry 'Red Hat Enterprise Linux Server (3.10.0-327.el7.x86_64) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	else
++	  search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	fi
++	linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet LANG=en_US.UTF-8
++	initrd16 /initramfs-3.10.0-327.el7.x86_64.img
++}
++menuentry 'Red Hat Enterprise Linux Server (0-rescue-925cd320373b6a4a9a66a26371afccd2) 7.2 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-925cd320373b6a4a9a66a26371afccd2-advanced-91b16928-66bf-4801-8aed-fab3f1a6876c' {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod xfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	else
++	  search --no-floppy --fs-uuid --set=root 7e972fc0-6cf8-4a58-ace6-1b381e52733d
++	fi
++	linux16 /vmlinuz-0-rescue-925cd320373b6a4a9a66a26371afccd2 root=/dev/mapper/rhel_team--area--222-root ro crashkernel=auto rd.lvm.lv=rhel_team-area-222/root rd.lvm.lv=rhel_team-area-222/swap rhgb quiet
++	initrd16 /initramfs-0-rescue-925cd320373b6a4a9a66a26371afccd2.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+-- 
+2.17.1
+
diff --git a/SOURCES/0023-Ensure-command-line-updates-also-honor-set-index.patch b/SOURCES/0023-Ensure-command-line-updates-also-honor-set-index.patch
new file mode 100644
index 0000000..ab4b1ac
--- /dev/null
+++ b/SOURCES/0023-Ensure-command-line-updates-also-honor-set-index.patch
@@ -0,0 +1,46 @@
+From f88808a37044c323e35eda49dbc326dcf260439b Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 24 Jun 2016 16:05:45 -0400
+Subject: [PATCH 23/55] Ensure command line updates also honor --set-index
+
+Related: rhbz#1285601
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/grubby.c b/grubby.c
+index 54625e7da0a..d889399449b 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -4212,11 +4212,17 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template,
+ 	struct singleEntry *new, *entry, *prev = NULL;
+ 	struct singleLine *newLine = NULL, *tmplLine = NULL, *masterLine = NULL;
+ 	int needs;
++	char *indexs;
+ 	char *chptr;
++	int rc;
+ 
+ 	if (!newKernelPath)
+ 		return 0;
+ 
++	rc = asprintf(&indexs, "%d", newIndex);
++	if (rc < 0)
++		return 1;
++
+ 	/* if the newKernelTitle is too long silently munge it into something
+ 	 * we can live with. truncating is first check, then we'll just mess with
+ 	 * it until it looks better */
+@@ -4715,7 +4721,7 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template,
+ 		abort();
+ 	}
+ 
+-	if (updateImage(config, "0", prefix, newKernelArgs, NULL,
++	if (updateImage(config, indexs, prefix, newKernelArgs, NULL,
+ 			newMBKernelArgs, NULL))
+ 		return 1;
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0024-Change-debug-entry-insertion-order-rhbz-1285601.patch b/SOURCES/0024-Change-debug-entry-insertion-order-rhbz-1285601.patch
new file mode 100644
index 0000000..1a05e8f
--- /dev/null
+++ b/SOURCES/0024-Change-debug-entry-insertion-order-rhbz-1285601.patch
@@ -0,0 +1,67 @@
+From fe9bc763507e849caa45926e49c1c324532ced6e Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 23 Jun 2016 14:41:12 -0400
+Subject: [PATCH 24/55] Change debug entry insertion order (rhbz#1285601)
+
+Customer reports indicated that it was confusing to have the debugging
+entries before non-debugging entries. Altered the insertion code to use
+the --set-index feature on the debug kernels to force them to insert
+after the initial non-debugging entry.
+
+Resolves: rhbz#1285601
+---
+ new-kernel-pkg | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index 9574dbbf10b..64225deb06b 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -244,7 +244,7 @@ install() {
+ 		--remove-kernel=\"TITLE=$title\$debugtitle\""
+ 
+ 	rungrubby ${ARGS} $makedefault
+-	rungrubby --debug ${ARGS}
++	rungrubby --debug ${ARGS} --set-index=1
+     else
+ 	[ -n "$verbose" ] && echo "$grubConfig does not exist, not running grubby for grub 0.97"
+     fi
+@@ -258,7 +258,7 @@ install() {
+ 		--args=\"root=$rootdevice $kernargs \$debugargs\" \
+ 		--remove-kernel=\"TITLE=$title\$debugtitle\""
+ 	rungrubby ${ARGS} $makedefault
+-	rungrubby --debug ${ARGS}
++	rungrubby --debug ${ARGS} --set-index=1
+     else
+ 	[ -n "$verbose" ] && echo "$grub2Config does not exist, not running grubby for grub 2"
+     fi
+@@ -273,7 +273,7 @@ install() {
+ 		--args=\"root=$rootdevice $kernargs \$debugargs\" \
+ 		--remove-kernel=\"TITLE=$title\$debugtitle\""
+ 	rungrubby ${ARGS} $makedefault
+-	rungrubby --debug ${ARGS}
++	rungrubby --debug ${ARGS} --set-index=1
+     else
+ 	[ -n "$verbose" ] && echo "$grub2EfiConfig does not exist, not running grubby for grub 2 with UEFI"
+     fi
+@@ -289,7 +289,7 @@ install() {
+ 		--remove-kernel=\"TITLE=$version\""
+ 
+ 	rungrubby ${ARGS} $makedefault
+-	rungrubby --debug ${ARGS}
++	rungrubby --debug ${ARGS} --set-index=1
+ 	if [ -n "$runLilo" ]; then
+ 	    [ -n "$verbose" ] && echo "running $lilo"
+ 	    if [ ! -x $lilo ] ; then
+@@ -314,7 +314,7 @@ install() {
+ 	    --remove-kernel=\"TITLE=$title\$debugtitle\""
+ 
+ 	rungrubby ${ARGS} $makedefault
+-	rungrubby --debug ${ARGS}
++	rungrubby --debug ${ARGS} --set-index=1
+     else
+ 	[ -n "$verbose" ] && echo "$extlinuxConfig does not exist, not running grubby for extlinux"
+     fi
+-- 
+2.17.1
+
diff --git a/SOURCES/0025-Reorganize-grubby-man-page-1232168.patch b/SOURCES/0025-Reorganize-grubby-man-page-1232168.patch
new file mode 100644
index 0000000..4247100
--- /dev/null
+++ b/SOURCES/0025-Reorganize-grubby-man-page-1232168.patch
@@ -0,0 +1,356 @@
+From 9073de7c059fcc9fd5ca837068d96cb0246f3c99 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Fri, 1 Jul 2016 14:03:38 -0400
+Subject: [PATCH 25/55] Reorganize grubby man page (#1232168)
+
+Broke the grubby man page into clearer sections and re-organized the
+content by general use case for easier reading.
+
+Related: rhbz#1232168
+---
+ grubby.8 | 220 ++++++++++++++++++++++++++++++-------------------------
+ 1 file changed, 120 insertions(+), 100 deletions(-)
+
+diff --git a/grubby.8 b/grubby.8
+index f1bfb9336e9..a3033d87254 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -1,15 +1,18 @@
+ .TH GRUBBY 8 "Tue Jan 18 2005"
++
+ .SH NAME
++
+ grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl
+ 
+ .SH SYNOPSIS
+-\fBgrubby\fR [--add-kernel=\fIkernel-path\fR] [--args=\fIargs\fR] 
+-       [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR] 
++
++\fBgrubby\fR [--add-kernel=\fIkernel-path\fR] [--args=\fIargs\fR]
++       [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR]
+        [--bootloader-probe] [--config-file \fIpath\fR] [--copy-default]
+        [--debug] [--default-kernel] [--default-index] [--default-title]
+        [--devtree=\fIdevicetree.dtb\fR] [--set-index=\fIentry-index\fR]
+        [--grub] [--lilo] [--yaboot] [--silo] [--zipl]
+-       [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR] 
++       [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR]
+        [--make-default] [-o path] [--version]
+        [--remove-kernel=\fIkernel-path\fR] [--remove-args=\fIargs\fR]
+        [--set-default=\fIkernel-path\fR] [--set-default-index=\fIentry-index\fR]
+@@ -18,12 +21,17 @@ grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl
+        [--remove-mbargs=\fIargs\fR]
+ 
+ .SH DESCRIPTION
++
++.SS General Information
++
+ \fBgrubby\fR is a command line tool for updating and displaying information
+ about the configuration files for the \fBgrub\fR, \fBlilo\fR, \fBelilo\fR
+ (ia64), \fByaboot\fR (powerpc) and \fBzipl\fR (s390) boot loaders. It
+ is primarily designed to be used from scripts which install new
+ kernels and need to find information about the current boot environment.
+ 
++.SS Architecture Support
++
+ On BIOS-based Intel x86 platforms, \fBgrub2\fR is the default bootloader and
+ the configuration file is in \fB/boot/grub2/grub.cfg\fR.  On UEFI-based Intel
+ x86 platforms, \fBgrub2\fR is the default bootloader, and the configuration
+@@ -35,6 +43,8 @@ config stored in \fB/boot/grub2/grub.cfg\fR. The earlier Power7 systems use \fBy
+ parsing and the configuration file should be in \fB/etc/yaboot.conf\fR.  On
+ s390 platforms the \fBzipl bootloader\fR will read from \fB/etc/zipl.conf\fR.
+ 
++.SS Special Arguments
++
+ There are a number of ways to specify the kernel used for \fB-\-info\fR,
+ \fB-\-remove-kernel\fR, and \fB-\-update-kernel\fR. Specificying \fBDEFAULT\fR
+ or \fBALL\fR selects the default entry and all of the entries, respectively.
+@@ -44,13 +54,24 @@ be specified by using \fBTITLE=\fItitle\fR as the argument; all entries
+ with that title are used.
+ 
+ .SH OPTIONS
++
++.SS Basic Options
++
+ .TP
+ \fB-\-add-kernel\fR=\fIkernel-path\fR
+ Add a new boot entry for the kernel located at \fIkernel-path\fR.
+ 
+ .TP
+-\fB-\-set-index\fR=\fIentry-index\fR
+-Set the position at which to add a new entry created with \fB-\-add-kernel\fR.
++\fB-\-remove-kernel\fR=\fIkernel-path\fR
++Removes all boot entries which match \fIkernel-path\fR. This may be used
++along with -\-add-kernel, in which case the new kernel being added will
++never be removed.
++
++.TP
++\fB-\-update-kernel\fR=\fIkernel-path\fR
++The entries for kernels matching \fRkernel-path\fR are updated. Currently
++the only items that can be updated is the kernel argument list, which is
++modified via the \fB-\-args\fR and \fB-\-remove-args\fR options.
+ 
+ .TP
+ \fB-\-args\fR=\fIkernel-args\fR
+@@ -65,38 +86,11 @@ file has special handling for specifying the root filesystem (like
+ lilo.conf does).
+ 
+ .TP
+-\fB-\-bad-image-okay\fR
+-When \fBgrubby\fR is looking for a entry to use for something (such
+-as a template or a default boot entry) it uses sanity checks, such as
+-ensuring that the kernel exists in the filesystem, to make sure
+-entries that obviously won't work aren't selected. This option overrides
+-that behavior, and is designed primarily for testing.
+-
+-.TP
+-\fB-\-boot-filesystem\fR=\fIbootfs\fR
+-The \fBgrub\fR boot loader expects file paths listed in it's configuration
+-path to be relative to the top of the filesystem they are on, rather then
+-relative to the current root filesystem. By default \fBgrubby\fR searches
+-the list of currently mounted filesystems to determine this. If this option
+-is given \fBgrubby\fR acts as if the specified filesystem was the filesystem
+-containing the kernel (this option is designed primarily for testing).
+-
+-.TP
+-\fB-\-bootloader-probe\fR
+-\fBgrubby\fR tries to determine if \fBgrub\fR or \fBlilo\fR is currently 
+-installed. When one of those bootloaders is found the name of that bootloader
+-is displayed on stdout.  Both could be installed (on different devices), and
+-grubby will print out the names of both bootloaders, one per line. The probe
+-for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR
+-identical to the standard directive in the lilo configuration file. If this
+-is not present \fBgrubby\fR will assume grub is not installed (note 
+-that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates).
+-This option is only available on ia32 platforms. 
+-
+-
+-.TP
+-\fB-\-config-file\fR=\fIpath\fR
+-Use \fIpath\fR as the configuration file rather then the default.
++\fB-\-remove-args\fR=\fIkernel-args\fR
++The arguments specified by \fIkernel-args\fR are removed from the
++kernels specified by \fB-\-update-kernel\fR. The \fBroot\fR argument
++gets special handling for configuration files that support separate root
++filesystem configuration.
+ 
+ .TP
+ \fB-\-copy-default\fR
+@@ -104,10 +98,41 @@ Use \fIpath\fR as the configuration file rather then the default.
+ root device) as possible from the current default kernel. The kernel path
+ and initrd path will never be copied.
+ 
++.TP
++\fB-\-title\fR=\fIentry-title\fR
++When a new kernel entry is added \fIentry-title\fR is used as the title
++(\fBlilo\fR label) for the entry. If \fIentry-title\fR is longer then maximum
++length allowed by the bootloader (15 for lilo, unlimited for grub and elilo)
++the title is shortened to a (unique) entry.
++
++.TP
++\fB-\-initrd\fR=\fIinitrd-path\fR
++Use \fIinitrd-path\fR as the path to an initial ram disk for a new kernel
++being added.
++
++.TP
++\fB-\-set-default\fR=\fIkernel-path\fR
++The first entry which boots the specified kernel is made the default
++boot entry.
++
++.TP
++\fB-\-set-default-index\fR=\fIentry-index\fR
++Makes the given entry number the default boot entry.
++
++.TP
++\fB-\-make-default\fR
++Make the new kernel entry being added the default entry.
++
++.TP
++\fB-\-set-index\fR=\fIentry-index\fR
++Set the position at which to add a new entry created with \fB-\-add-kernel\fR.
++
+ .TP
+ \fB-\-debug\fR
+ Display extra debugging information for failures.
+ 
++.SS Display Options
++
+ .TP
+ \fB-\-default-kernel\fR
+ Display the full path to the current default kernel and exit.
+@@ -121,9 +146,26 @@ Display the numeric index of the current default boot entry and exit.
+ Display the title of the current default boot entry and exit.
+ 
+ .TP
+-\fB-\-devtree\fR=\fIpath\fR
+-Use \fIpath\fR for device tree path in place of the path of any devicetree
+-directive found in the template stanza.
++\fB-\-info\fR=\fIkernel-path\fR
++Display information on all boot entries which match \fIkernel-path\fR. I
++
++.TP
++\fB-\-bootloader-probe\fR
++\fBgrubby\fR tries to determine if \fBgrub\fR or \fBlilo\fR is currently
++installed. When one of those bootloaders is found the name of that bootloader
++is displayed on stdout.  Both could be installed (on different devices), and
++grubby will print out the names of both bootloaders, one per line. The probe
++for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR
++identical to the standard directive in the lilo configuration file. If this
++is not present \fBgrubby\fR will assume grub is not installed (note
++that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates).
++This option is only available on ia32 platforms.
++
++.TP
++\fB-\-version\fR
++Display the version of \fBgrubby\fR being run and then exit immediately.
++
++.SS Output Format Options
+ 
+ .TP
+ \fB-\-elilo\fR
+@@ -134,62 +176,10 @@ Use an \fBelilo\fR style configuration file.
+ Use a \fBgrub\fR style configuration file instead of \fBlilo\fR style. This
+ is the default on ia32 platforms.
+ 
+-.TP
+-\fB-\-info\fR=\fIkernel-path\fR
+-Display information on all boot entries which match \fIkernel-path\fR. I
+-
+-.TP
+-\fB-\-initrd\fR=\fIinitrd-path\fR
+-Use \fIinitrd-path\fR as the path to an initial ram disk for a new kernel
+-being added.
+-
+ .TP
+ \fB-\-lilo\fR
+ Use a \fBlilo\fR style configuration file.
+ 
+-.TP
+-\fB-\-make-default\fR
+-Make the new kernel entry being added the default entry.
+-
+-.TP
+-\fB-\-remove-args\fR=\fIkernel-args\fR
+-The arguments specified by \fIkernel-args\fR are removed from the 
+-kernels specified by \fB-\-update-kernel\fR. The \fBroot\fR argument
+-gets special handling for configuration files that support separate root
+-filesystem configuration.
+-
+-.TP
+-\fB-\-remove-kernel\fR=\fIkernel-path\fR
+-Removes all boot entries which match \fIkernel-path\fR. This may be used
+-along with -\-add-kernel, in which case the new kernel being added will
+-never be removed.
+-
+-.TP
+-\fB-\-set-default\fR=\fIkernel-path\fR
+-The first entry which boots the specified kernel is made the default
+-boot entry.
+-
+-.TP
+-\fB-\-set-default-index\fR=\fIentry-index\fR
+-Makes the given entry number the default boot entry.
+-
+-.TP
+-\fB-\-title\fR=\fIentry-title\fR
+-When a new kernel entry is added \fIentry-title\fR is used as the title
+-(\fBlilo\fR label) for the entry. If \fIentry-title\fR is longer then maximum
+-length allowed by the bootloader (15 for lilo, unlimited for grub and elilo)
+-the title is shortened to a (unique) entry.
+-
+-.TP
+-\fB-\-update-kernel\fR=\fIkernel-path\fR
+-The entries for kernels matching \fRkernel-path\fR are updated. Currently
+-the only items that can be updated is the kernel argument list, which is
+-modified via the \fB-\-args\fR and \fB-\-remove-args\fR options.
+-
+-.TP
+-\fB-\-version\fR
+-Display the version of \fBgrubby\fR being run and then exit immediately.
+-
+ .TP
+ \fB-\-yaboot\fR
+ Use an \fByaboot\fR style configuration file.
+@@ -198,7 +188,35 @@ Use an \fByaboot\fR style configuration file.
+ \fB-\-zipl\fR
+ Use an \fBzipl\fR style configuration file.
+ 
+-.SH MULTIBOOT OPTIONS
++.SS Override Options
++
++.TP
++\fB-\-bad-image-okay\fR
++When \fBgrubby\fR is looking for a entry to use for something (such
++as a template or a default boot entry) it uses sanity checks, such as
++ensuring that the kernel exists in the filesystem, to make sure
++entries that obviously won't work aren't selected. This option overrides
++that behavior, and is designed primarily for testing.
++
++.TP
++\fB-\-boot-filesystem\fR=\fIbootfs\fR
++The \fBgrub\fR boot loader expects file paths listed in it's configuration
++path to be relative to the top of the filesystem they are on, rather then
++relative to the current root filesystem. By default \fBgrubby\fR searches
++the list of currently mounted filesystems to determine this. If this option
++is given \fBgrubby\fR acts as if the specified filesystem was the filesystem
++containing the kernel (this option is designed primarily for testing).
++
++.TP
++\fB-\-config-file\fR=\fIpath\fR
++Use \fIpath\fR as the configuration file rather then the default.
++
++\fB-\-devtree\fR=\fIpath\fR
++Use \fIpath\fR for device tree path in place of the path of any devicetree
++directive found in the template stanza.
++
++.SS Multiboot Options
++
+ The Multiboot Specification provides a genreic interface for boot
+ loaders and operating systems.  It is supported by the GRUB bootloader.
+ 
+@@ -210,34 +228,36 @@ Add a new boot entry for the multiboot kernel located at
+ 
+ .TP
+ \fB-\-remove-multiboot\fR=\fImultiboot-path\fR
+-Removes all boot entries which match \fImultiboot-path\fR. 
++Removes all boot entries which match \fImultiboot-path\fR.
+ 
+ .TP
+ \fB-\-mbargs\fR=\fImultiboot-args\fR
+-When a new multiboot kernel is added, this specifies the command line 
+-arguments which should be passed to that kernel by default 
++When a new multiboot kernel is added, this specifies the command line
++arguments which should be passed to that kernel by default
+ When \fB-\-update-kernel\fR is used, this specifies new arguments to add
+ to the argument list. Multiple, space separated arguments may be used. If
+-an argument already exists the new value replaces the old values. 
++an argument already exists the new value replaces the old values.
+ 
+ .TP
+ \fB-\-remove-mbargs\fR=\fImultiboot-args\fR
+-The arguments specified by \fImultiboot-args\fR are removed from the 
+-kernels specified by \fB-\-update-kernel\fR. 
+-
++The arguments specified by \fImultiboot-args\fR are removed from the
++kernels specified by \fB-\-update-kernel\fR.
+ 
+ .SH "BUGS"
++
+ The command line syntax is more than a little baroque. This probably
+ won't be fixed as \fBgrubby\fR is only intended to be called from shell
+ scripts which can get it right.
+ 
+ .SH "SEE ALSO"
++
+ .BR grub (8),
+ .BR lilo (8),
+ .BR yaboot (8),
+ .BR mkinitrd (8)
+ 
+ .SH AUTHORS
++
+ .nf
+ Erik Troan
+ Jeremy Katz
+-- 
+2.17.1
+
diff --git a/SOURCES/0026-Update-grubby-man-page-contents-bz1232168.patch b/SOURCES/0026-Update-grubby-man-page-contents-bz1232168.patch
new file mode 100644
index 0000000..ca33608
--- /dev/null
+++ b/SOURCES/0026-Update-grubby-man-page-contents-bz1232168.patch
@@ -0,0 +1,369 @@
+From e08236e8d15ff0fc581d56efaf4d855c57d6d994 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Fri, 1 Jul 2016 15:03:13 -0400
+Subject: [PATCH 26/55] Update grubby man page contents (#bz1232168)
+
+The grubby man page was missing several options that were added in
+previous releases. Added those to the man page as well as updated the
+text on others to provide further clarity.
+
+Added an EXAMPLE section containing some basic use cases.
+
+Resolves: rhbz#1232168
+---
+ grubby.8 | 218 +++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 173 insertions(+), 45 deletions(-)
+
+diff --git a/grubby.8 b/grubby.8
+index a3033d87254..64a6984fba0 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -2,51 +2,69 @@
+ 
+ .SH NAME
+ 
+-grubby \- command line tool for configuring grub, lilo, elilo, yaboot and zipl
++grubby \- command line tool used to configure bootloader menu entries across multiple architectures
+ 
+ .SH SYNOPSIS
+ 
+-\fBgrubby\fR [--add-kernel=\fIkernel-path\fR] [--args=\fIargs\fR]
+-       [--bad-image-okay] [--boot-filesystem=\fIbootfs\fR]
+-       [--bootloader-probe] [--config-file \fIpath\fR] [--copy-default]
+-       [--debug] [--default-kernel] [--default-index] [--default-title]
+-       [--devtree=\fIdevicetree.dtb\fR] [--set-index=\fIentry-index\fR]
+-       [--grub] [--lilo] [--yaboot] [--silo] [--zipl]
+-       [--info=\fIkernel-path\fR] [--initrd=\fIinitrd-path\fR]
+-       [--make-default] [-o path] [--version]
+-       [--remove-kernel=\fIkernel-path\fR] [--remove-args=\fIargs\fR]
+-       [--set-default=\fIkernel-path\fR] [--set-default-index=\fIentry-index\fR]
+-       [--title=entry-title] [--add-multiboot=\fImultiboot-path\fR]
+-       [--mbargs=\fIargs\fR] [--remove-multiboot=\fImultiboot-path\fR]
+-       [--remove-mbargs=\fIargs\fR]
++\fBgrubby\fR [\fIOPTIONS...\fR]
+ 
+ .SH DESCRIPTION
+ 
+ .SS General Information
+ 
+ \fBgrubby\fR is a command line tool for updating and displaying information
+-about the configuration files for the \fBgrub\fR, \fBlilo\fR, \fBelilo\fR
+-(ia64), \fByaboot\fR (powerpc) and \fBzipl\fR (s390) boot loaders. It
+-is primarily designed to be used from scripts which install new
+-kernels and need to find information about the current boot environment.
++about the configuration files for various architecture specific bootloaders.
++It is primarily designed to be used from scripts which install new kernels
++and need to find information about the current boot environment.
+ 
+ .SS Architecture Support
+ 
+-On BIOS-based Intel x86 platforms, \fBgrub2\fR is the default bootloader and
+-the configuration file is in \fB/boot/grub2/grub.cfg\fR.  On UEFI-based Intel
+-x86 platforms, \fBgrub2\fR is the default bootloader, and the configuration
+-file is in \fB/boot/efi/EFI/redhat/grub.cfg\fR.  On Intel ia64 platforms,
+-\fBelilo\fR mode is used and the default location for the configuration file
+-is \fB/boot/efi/EFI/redhat/elilo.conf\fR. On PowerPC platforms, systems based
+-on Power8 now support \fBgrub2\fR as a bootloader and store using a default
+-config stored in \fB/boot/grub2/grub.cfg\fR. The earlier Power7 systems use \fByaboot\fR
+-parsing and the configuration file should be in \fB/etc/yaboot.conf\fR.  On
+-s390 platforms the \fBzipl bootloader\fR will read from \fB/etc/zipl.conf\fR.
++The \fBgrubby\fR executable has full support for the \fBgrub2\fR
++bootloader on \fBx86_64\fR systems using legacy BIOS or modern
++UEFI firmware and \fBppc64\fR and \fBppc64le\fR hardware using
++OPAL or SLOF as firmware.
++
++Legacy \fBs390\fR and the current \fBs390x\fR architectures
++and their \fBzipl\fR bootloader are fully supported.
++
++Support for \fByaboot\fR has been deprecated as all ppc architecture
++hardware since the Power8 system uses \fBgrub2\fR or petitboot
++which both use the grub2 configuration file format.
++
++Legacy bootloaders \fBLILO\fR, \fBSILO\fR, and \fBELILO\fR
++are deprecated in favor of previously mentioned bootloaders. The
++\fBSILO\fR bootloader should also be considered unsupported.
++
++.SS Default Behavior
++
++The default architecture is chosen at compile time. The grubby executable
++has a series of built in assumptions about what bootloader is being used and
++where its configuration file lives. If no output format option is specified
++on the command line then grubby will use these default settings to first
++search for an existing configuration and, if it is not found, assume that
++it should be placed in the standard location. These default assumptions are
++listed in the table below.
++
++.TS
++allbox;
++lbw6 lbw10 lbw18
++l l l.
++ Arch	Bootloader	Configuration File
++ x86_64 [BIOS]	grub2	/boot/grub2/grub.cfg
++ x86_64 [UEFI]	grub2	/boot/efi/EFI/redhat/grub.cfg
++ i386	grub2	/boot/grub2/grub.cfg
++ ia64	elilo	/boot/efi/EFI/redhat/elilo.conf
++ ppc [>=Power8]	grub2	/boot/grub2/grub.cfg
++ ppc [<=Power7]	yaboot	/etc/yaboot.conf
++ s390	zipl	/etc/zipl.conf
++ s390x	zipl	/etc/zipl.conf
++.TE
++
+ 
+ .SS Special Arguments
+ 
+ There are a number of ways to specify the kernel used for \fB-\-info\fR,
+-\fB-\-remove-kernel\fR, and \fB-\-update-kernel\fR. Specificying \fBDEFAULT\fR
++\fB-\-remove-kernel\fR, and \fB-\-update-kernel\fR. Specifying \fBDEFAULT\fR
+ or \fBALL\fR selects the default entry and all of the entries, respectively.
+ If a comma separated list of numbers is given, the boot entries indexed
+ by those numbers are selected. Finally, the title of a boot entry may
+@@ -59,12 +77,17 @@ with that title are used.
+ 
+ .TP
+ \fB-\-add-kernel\fR=\fIkernel-path\fR
+-Add a new boot entry for the kernel located at \fIkernel-path\fR.
++Add a new boot entry for the kernel located at \fIkernel-path\fR. A title for
++the boot entry must be set using \fB-\-title\fR. Most invocations should also
++include \fB-\-initrd\fR with memtest86 as a notable exception.
++
++The \fB-\-update-kernel\fR
++option may not be used in the same invocation. 
+ 
+ .TP
+ \fB-\-remove-kernel\fR=\fIkernel-path\fR
+ Removes all boot entries which match \fIkernel-path\fR. This may be used
+-along with -\-add-kernel, in which case the new kernel being added will
++along with \fB-\-add-kernel\fR, in which case the new kernel being added will
+ never be removed.
+ 
+ .TP
+@@ -110,14 +133,19 @@ the title is shortened to a (unique) entry.
+ Use \fIinitrd-path\fR as the path to an initial ram disk for a new kernel
+ being added.
+ 
++.TP
++\fB-\-efi\fR
++Use linuxefi and initrdefi when constructing bootloader stanzas instead of linux and initrd.
++
+ .TP
+ \fB-\-set-default\fR=\fIkernel-path\fR
+ The first entry which boots the specified kernel is made the default
+-boot entry.
++boot entry. This may not be invoked with \fB-\-set-default-index\fR.
+ 
+ .TP
+ \fB-\-set-default-index\fR=\fIentry-index\fR
+-Makes the given entry number the default boot entry.
++Makes the given entry number the default boot entry. This may not
++be invoked with \fB-\-set-default\fR.
+ 
+ .TP
+ \fB-\-make-default\fR
+@@ -131,8 +159,17 @@ Set the position at which to add a new entry created with \fB-\-add-kernel\fR.
+ \fB-\-debug\fR
+ Display extra debugging information for failures.
+ 
++.TP
++\fB-i\fR, \fB-\-extra-initrd\fR=\fIinitrd-path\fR
++Use \fIinitrd-path\fR as the path for an auxiliary initrd image.
++
+ .SS Display Options
+ 
++Passing the display option to grubby will cause it to print out the
++requested information about the current bootloader configuration and
++then immediately exit.  These options should not be used in any
++script intended to update the bootloader configuration.
++
+ .TP
+ \fB-\-default-kernel\fR
+ Display the full path to the current default kernel and exit.
+@@ -159,34 +196,56 @@ for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR
+ identical to the standard directive in the lilo configuration file. If this
+ is not present \fBgrubby\fR will assume grub is not installed (note
+ that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates).
+-This option is only available on ia32 platforms.
++
++\fIThis option is only available on i386 platforms.\fR
+ 
+ .TP
+-\fB-\-version\fR
++\fB-v\fR, \fB-\-version\fR
+ Display the version of \fBgrubby\fR being run and then exit immediately.
+ 
+ .SS Output Format Options
+ 
++Sane default options for the current platform are compiled into grubby on
++a per platform basis. These defaults determine the format and layout of
++the generated bootloader configuration file. A different configuration file
++format may be specified on the command line if the system uses a supported
++alternative bootloader.
++
+ .TP
+ \fB-\-elilo\fR
+-Use an \fBelilo\fR style configuration file.
++Use an \fBelilo\fR style configuration file. This is the default on ia64 platforms. This format is deprecated.
++
++.TP
++\fB-\-extlinux\fR
++Use an \fBextlinux\fR style configuration file. This format is deprecated.
+ 
+ .TP
+ \fB-\-grub\fR
+-Use a \fBgrub\fR style configuration file instead of \fBlilo\fR style. This
+-is the default on ia32 platforms.
++Use a \fBgrub\fR style configuration file. This is the default on ia32 platforms.
++
++.TP
++\fB-\-grub2\fR
++Use a \fBgrub2\fR style configuration file. This is the default on \fBx86_64\fR
++architecture as well as the \fBppc64\fR and \fBppc64le\fR architectures
++running on Power8 or later hardware.
+ 
+ .TP
+ \fB-\-lilo\fR
+ Use a \fBlilo\fR style configuration file.
+ 
++.TP
++\fB-\-silo\fR
++Use a \fBsilo\fR style configuration file. This is the default on SPARC systems. This format is legacy, deprecated, and unsupported.
++
+ .TP
+ \fB-\-yaboot\fR
+-Use an \fByaboot\fR style configuration file.
++Use a \fByaboot\fR style configuration file. This is the default for
++the \fBppc\fR architecture on on Power7 and earlier hardware.
+ 
+ .TP
+ \fB-\-zipl\fR
+-Use an \fBzipl\fR style configuration file.
++Use a \fBzipl\fR style configuration file. This is the default on the
++legacy s390 and current s390x architectures.
+ 
+ .SS Override Options
+ 
+@@ -200,7 +259,7 @@ that behavior, and is designed primarily for testing.
+ 
+ .TP
+ \fB-\-boot-filesystem\fR=\fIbootfs\fR
+-The \fBgrub\fR boot loader expects file paths listed in it's configuration
++The \fBgrub\fR boot loader expects file paths listed in its configuration
+ path to be relative to the top of the filesystem they are on, rather then
+ relative to the current root filesystem. By default \fBgrubby\fR searches
+ the list of currently mounted filesystems to determine this. If this option
+@@ -208,23 +267,39 @@ is given \fBgrubby\fR acts as if the specified filesystem was the filesystem
+ containing the kernel (this option is designed primarily for testing).
+ 
+ .TP
+-\fB-\-config-file\fR=\fIpath\fR
++\fB-\-env\fR=\fIpath\fR
++Path for the file where grub environment data is stored.
++
++.TP
++\fB-c\fR, \fB-\-config-file\fR=\fIpath\fR
+ Use \fIpath\fR as the configuration file rather then the default.
+ 
+-\fB-\-devtree\fR=\fIpath\fR
++.TP
++\fB-o\fR, \fB-\-output-file\fR=\fIfile_path\fR
++The destination path for the updated configuration file. Use "-" to
++send it to stdout.
++
++.TP
++\fB-\-devtree\fR=\fIfile_path\fR
+ Use \fIpath\fR for device tree path in place of the path of any devicetree
+ directive found in the template stanza.
+ 
++.TP
++\fB-\-devtreedir\fR=\fIfile_path\fR
++Use the specified \fIfile path\fR to load the devicetree definition. This is for
++platforms where a flat file is used instead of firmware to instruct the kernel
++how to communicate with devices.
++
+ .SS Multiboot Options
+ 
+-The Multiboot Specification provides a genreic interface for boot
++The Multiboot Specification provides a generic interface for boot
+ loaders and operating systems.  It is supported by the GRUB bootloader.
+ 
+ .TP
+ \fB-\-add-multiboot\fR=\fImultiboot-path\fR
+ Add a new boot entry for the multiboot kernel located at
+ \fImultiboot-path\fR.  Note that this is generally accompanied with a
+-\fI--add-kernel\fR option.
++\fB--add-kernel\fR option.
+ 
+ .TP
+ \fB-\-remove-multiboot\fR=\fImultiboot-path\fR
+@@ -249,11 +324,63 @@ The command line syntax is more than a little baroque. This probably
+ won't be fixed as \fBgrubby\fR is only intended to be called from shell
+ scripts which can get it right.
+ 
++.SH EXAMPLE
++
++The following examples assume the following:
++
++.TS
++allbox;
++rbw15 l.
++cfg_file	Full path to bootloader config file
++new_kernel	Full path to kernel image to be installed
++old_kernel	Full path to old kernel image to be removed
++current_kernel	Full path to a currently installed kernel
++entry_title	Title that appears on bootloader menu
++new_initrd	Full path to initrd for a new kernel
++kernel_args	Set of arguments for the kernel
++menu_index	Index number of a menu entry
++.TE
++
++The examples below quote strings that may have spaces or other whitespace in them. It is also
++perfectly valid to backslash escape these strings if that is more convenient.
++
++.PP
++Add a new kernel entry and copy all options from the current default kernel. This is the behavior
++that most users will want.
++.IP
++\fBgrubby\fR --add-kernel=\fInew_kernel\fR --title="\fIentry_title\fR" --initrd="\fInew_initrd\fR" --copy-default
++.PP
++Add a new kernel entry with custom arguments
++.IP
++\fBgrubby\fR --add-kernel=\fInew_kernel\fR --title="\fIentry_title\fR" --initrd="\fInew_initrd\fR" --args=\fIkernel_args\fR
++.PP
++Remove \fBall menu entries\fR for a specified kernel.
++.IP
++\fBgrubby\fR --remove-kernel=\fIold_kernel\fR
++.PP
++Target a single menu entry to remove without targetting other entries with the same kernel.
++.IP
++\fBgrubby\fR --info=\fIold_kernel\fR
++
++\fBgrubby\fR --remove-kernel=\fImenu_index\fR
++.PP
++Update the arguments for all entries of a specific kernel. New arguments get added while existing arguments get updated values.
++.IP
++\fBgrubby\fR --update-kernel=\fIcurrent_kernel\fR --args="\fIkernel_args\fR"
++.PP
++Remove the arguments for a single entry of a specific kernel.
++.IP
++\fBgrubby\fR --info=\fIcurrent_kernel\fR
++
++\fBgrubby\fR --remove-args=\fImenu_index\fR --args="\fIkernel_args\fR"
++
+ .SH "SEE ALSO"
+ 
+ .BR grub (8),
+ .BR lilo (8),
+ .BR yaboot (8),
++.BR zipl (8),
++.BR dracut (8),
+ .BR mkinitrd (8)
+ 
+ .SH AUTHORS
+@@ -262,4 +389,5 @@ scripts which can get it right.
+ Erik Troan
+ Jeremy Katz
+ Peter Jones
++Robert Marshall
+ .fi
+-- 
+2.17.1
+
diff --git a/SOURCES/0027-Fix-inline-help-typo-1232168.patch b/SOURCES/0027-Fix-inline-help-typo-1232168.patch
new file mode 100644
index 0000000..54c9521
--- /dev/null
+++ b/SOURCES/0027-Fix-inline-help-typo-1232168.patch
@@ -0,0 +1,29 @@
+From 850fbd8b0dcc728653993661b92349f3eb2b39a6 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 28 Jun 2016 16:26:32 -0400
+Subject: [PATCH 27/55] Fix inline help typo (#1232168)
+
+Discovered a typo while synchronizing the inline help with the man pages
+and fixed it.
+
+Related: rhbz#1232168
+---
+ grubby.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grubby.c b/grubby.c
+index d889399449b..e2384c55898 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -4786,7 +4786,7 @@ int main(int argc, const char **argv)
+ 		 NULL},
+ 		{"boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
+ 		 _
+-		 ("filestystem which contains /boot directory (for testing only)"),
++		 ("filesystem which contains /boot directory (for testing only)"),
+ 		 _("bootfs")},
+ #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
+ 		{"bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
+-- 
+2.17.1
+
diff --git a/SOURCES/0028-More-edits-for-grubby.8-1232168.patch b/SOURCES/0028-More-edits-for-grubby.8-1232168.patch
new file mode 100644
index 0000000..d9db478
--- /dev/null
+++ b/SOURCES/0028-More-edits-for-grubby.8-1232168.patch
@@ -0,0 +1,213 @@
+From b24cd1c5c8467ac6f7c5680db3a49ef6adc8df21 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 28 Jun 2016 16:50:37 -0400
+Subject: [PATCH 28/55] More edits for grubby.8 (#1232168)
+
+- Don't switch between the passive and active voice between the option
+  descriptions
+- keep the same point of view between options ("[it] removes all
+  entries" vs "remove all entries")
+- line wrap everywhere except the example envocations at <80 columns,
+  not 100.
+- consistent use of i386 vs ia32
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+
+Related: rhbz#1232168
+---
+ grubby.8 | 88 ++++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 48 insertions(+), 40 deletions(-)
+
+diff --git a/grubby.8 b/grubby.8
+index 64a6984fba0..690676858ca 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -2,11 +2,12 @@
+ 
+ .SH NAME
+ 
+-grubby \- command line tool used to configure bootloader menu entries across multiple architectures
++grubby \- command line tool used to configure bootloader menu entries across
++multiple architectures
+ 
+ .SH SYNOPSIS
+ 
+-\fBgrubby\fR [\fIOPTIONS...\fR]
++\fBgrubby\fR [\fIOPTIONS\fR]
+ 
+ .SH DESCRIPTION
+ 
+@@ -37,13 +38,13 @@ are deprecated in favor of previously mentioned bootloaders. The
+ 
+ .SS Default Behavior
+ 
+-The default architecture is chosen at compile time. The grubby executable
+-has a series of built in assumptions about what bootloader is being used and
+-where its configuration file lives. If no output format option is specified
+-on the command line then grubby will use these default settings to first
+-search for an existing configuration and, if it is not found, assume that
+-it should be placed in the standard location. These default assumptions are
+-listed in the table below.
++The default bootloader target is primarily determined by the architecture
++for which grubby has been built.  Each architecture has a preferred
++bootloader, and each bootloader has its own configuration file.  If no
++bootloader is selected on the command line, grubby will use these default
++settings to search for an existing configuration.  If no bootloader
++configuration file is found, grubby will use the default value for that
++architecture.  These defaults are listed in the table below.
+ 
+ .TS
+ allbox;
+@@ -81,19 +82,18 @@ Add a new boot entry for the kernel located at \fIkernel-path\fR. A title for
+ the boot entry must be set using \fB-\-title\fR. Most invocations should also
+ include \fB-\-initrd\fR with memtest86 as a notable exception.
+ 
+-The \fB-\-update-kernel\fR
+-option may not be used in the same invocation. 
++The \fB-\-update-kernel\fR option may not be used in the same invocation.
+ 
+ .TP
+ \fB-\-remove-kernel\fR=\fIkernel-path\fR
+-Removes all boot entries which match \fIkernel-path\fR. This may be used
+-along with \fB-\-add-kernel\fR, in which case the new kernel being added will
+-never be removed.
++Remove all boot entries which match \fIkernel-path\fR. This may be used
++along with \fB-\-add-kernel\fR, in which case the new entry being added will
++not be removed.
+ 
+ .TP
+ \fB-\-update-kernel\fR=\fIkernel-path\fR
+-The entries for kernels matching \fRkernel-path\fR are updated. Currently
+-the only items that can be updated is the kernel argument list, which is
++Update the entries for kernels matching \fRkernel-path\fR. Currently
++the only item that can be updated is the kernel argument list, which is
+ modified via the \fB-\-args\fR and \fB-\-remove-args\fR options.
+ 
+ .TP
+@@ -135,7 +135,7 @@ being added.
+ 
+ .TP
+ \fB-\-efi\fR
+-Use linuxefi and initrdefi when constructing bootloader stanzas instead of linux and initrd.
++Use appropriate bootloader commands for EFI on this architecture.
+ 
+ .TP
+ \fB-\-set-default\fR=\fIkernel-path\fR
+@@ -188,16 +188,18 @@ Display information on all boot entries which match \fIkernel-path\fR. I
+ 
+ .TP
+ \fB-\-bootloader-probe\fR
++Attempt to probe for installed bootloaders.  If this option is specified,
+ \fBgrubby\fR tries to determine if \fBgrub\fR or \fBlilo\fR is currently
+-installed. When one of those bootloaders is found the name of that bootloader
+-is displayed on stdout.  Both could be installed (on different devices), and
+-grubby will print out the names of both bootloaders, one per line. The probe
+-for \fBgrub\fR requires a commented out boot directive \fBgrub.conf\fR
+-identical to the standard directive in the lilo configuration file. If this
+-is not present \fBgrubby\fR will assume grub is not installed (note
+-that \fBanaconda\fR places this directive in \fBgrub.conf\fR files it creates).
++installed. When one of those bootloaders is found the name of that
++bootloader is displayed on stdout.  Both could be installed (on different
++devices), and grubby will print out the names of both bootloaders, one per
++line. The probe for \fBgrub\fR requires a commented out boot directive
++\fBgrub.conf\fR identical to the standard directive in the lilo
++configuration file. If this is not present \fBgrubby\fR will assume grub is
++not installed (note that \fBanaconda\fR places this directive in
++\fBgrub.conf\fR files it creates).
+ 
+-\fIThis option is only available on i386 platforms.\fR
++\fIThis option is only available on x86 BIOS platforms.\fR
+ 
+ .TP
+ \fB-v\fR, \fB-\-version\fR
+@@ -213,7 +215,8 @@ alternative bootloader.
+ 
+ .TP
+ \fB-\-elilo\fR
+-Use an \fBelilo\fR style configuration file. This is the default on ia64 platforms. This format is deprecated.
++Use an \fBelilo\fR style configuration file. This is the default on ia64
++platforms. This format is deprecated.
+ 
+ .TP
+ \fB-\-extlinux\fR
+@@ -221,13 +224,14 @@ Use an \fBextlinux\fR style configuration file. This format is deprecated.
+ 
+ .TP
+ \fB-\-grub\fR
+-Use a \fBgrub\fR style configuration file. This is the default on ia32 platforms.
++Use a \fBgrub\fR style configuration file. This is the default on the i386
++architecture.
+ 
+ .TP
+ \fB-\-grub2\fR
+-Use a \fBgrub2\fR style configuration file. This is the default on \fBx86_64\fR
+-architecture as well as the \fBppc64\fR and \fBppc64le\fR architectures
+-running on Power8 or later hardware.
++Use a \fBgrub2\fR style configuration file. This is the default on
++\fBx86_64\fR architecture as well as the \fBppc64\fR and \fBppc64le\fR
++architectures running on Power8 or later hardware.
+ 
+ .TP
+ \fB-\-lilo\fR
+@@ -235,7 +239,8 @@ Use a \fBlilo\fR style configuration file.
+ 
+ .TP
+ \fB-\-silo\fR
+-Use a \fBsilo\fR style configuration file. This is the default on SPARC systems. This format is legacy, deprecated, and unsupported.
++Use a \fBsilo\fR style configuration file. This is the default on SPARC
++systems. This format is legacy, deprecated, and unsupported.
+ 
+ .TP
+ \fB-\-yaboot\fR
+@@ -286,9 +291,9 @@ directive found in the template stanza.
+ 
+ .TP
+ \fB-\-devtreedir\fR=\fIfile_path\fR
+-Use the specified \fIfile path\fR to load the devicetree definition. This is for
+-platforms where a flat file is used instead of firmware to instruct the kernel
+-how to communicate with devices.
++Use the specified \fIfile path\fR to load the devicetree definition. This is
++for platforms where a flat file is used instead of firmware to instruct the
++kernel how to communicate with devices.
+ 
+ .SS Multiboot Options
+ 
+@@ -341,12 +346,13 @@ kernel_args	Set of arguments for the kernel
+ menu_index	Index number of a menu entry
+ .TE
+ 
+-The examples below quote strings that may have spaces or other whitespace in them. It is also
+-perfectly valid to backslash escape these strings if that is more convenient.
++The examples below quote strings that may have spaces or other whitespace in
++them. It is also perfectly valid to backslash escape these strings if that
++is more convenient.
+ 
+ .PP
+-Add a new kernel entry and copy all options from the current default kernel. This is the behavior
+-that most users will want.
++Add a new kernel entry and copy all options from the current default kernel.
++This is the behavior that most users will want.
+ .IP
+ \fBgrubby\fR --add-kernel=\fInew_kernel\fR --title="\fIentry_title\fR" --initrd="\fInew_initrd\fR" --copy-default
+ .PP
+@@ -358,13 +364,15 @@ Remove \fBall menu entries\fR for a specified kernel.
+ .IP
+ \fBgrubby\fR --remove-kernel=\fIold_kernel\fR
+ .PP
+-Target a single menu entry to remove without targetting other entries with the same kernel.
++Target a single menu entry to remove without targetting other entries with
++the same kernel.
+ .IP
+ \fBgrubby\fR --info=\fIold_kernel\fR
+ 
+ \fBgrubby\fR --remove-kernel=\fImenu_index\fR
+ .PP
+-Update the arguments for all entries of a specific kernel. New arguments get added while existing arguments get updated values.
++Update the arguments for all entries of a specific kernel. New arguments get
++added while existing arguments get updated values.
+ .IP
+ \fBgrubby\fR --update-kernel=\fIcurrent_kernel\fR --args="\fIkernel_args\fR"
+ .PP
+-- 
+2.17.1
+
diff --git a/SOURCES/0029-Minor-man-page-changes-1232168.patch b/SOURCES/0029-Minor-man-page-changes-1232168.patch
new file mode 100644
index 0000000..ba7bd9e
--- /dev/null
+++ b/SOURCES/0029-Minor-man-page-changes-1232168.patch
@@ -0,0 +1,36 @@
+From 79651f6be03752ecaefc9c77e2460e1763f6c0ea Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Fri, 1 Jul 2016 14:24:27 -0400
+Subject: [PATCH 29/55] Minor man page changes (#1232168)
+
+Minor wording changes made in the Architecture section after placing the
+initial draft up for public comment.
+
+Related: rhbz#1232168
+---
+ grubby.8 | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/grubby.8 b/grubby.8
+index 690676858ca..fdf2766fe9a 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -29,12 +29,12 @@ Legacy \fBs390\fR and the current \fBs390x\fR architectures
+ and their \fBzipl\fR bootloader are fully supported.
+ 
+ Support for \fByaboot\fR has been deprecated as all ppc architecture
+-hardware since the Power8 system uses \fBgrub2\fR or petitboot
++hardware since the Power8 uses \fBgrub2\fR or petitboot
+ which both use the grub2 configuration file format.
+ 
+ Legacy bootloaders \fBLILO\fR, \fBSILO\fR, and \fBELILO\fR
+-are deprecated in favor of previously mentioned bootloaders. The
+-\fBSILO\fR bootloader should also be considered unsupported.
++are deprecated and no longer receiving active support in favor of
++previously mentioned bootloaders.
+ 
+ .SS Default Behavior
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0030-Rename-setDefaultImage-variables.patch b/SOURCES/0030-Rename-setDefaultImage-variables.patch
new file mode 100644
index 0000000..3f5d3ea
--- /dev/null
+++ b/SOURCES/0030-Rename-setDefaultImage-variables.patch
@@ -0,0 +1,66 @@
+From 7b34b49d2a08a2636e0319b94d72ab654a30343d Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 8 Dec 2016 13:39:22 -0500
+Subject: [PATCH 30/55] Rename setDefaultImage variables
+
+The variable names in setDefaultImage did not match well with
+how they were being used inside the function. Refactored the
+variable names as a precursor to refactoring the function.
+
+Related: rhbz#1285601
+---
+ grubby.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index e2384c55898..9af8d17b345 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -2491,19 +2491,19 @@ void markRemovedImage(struct grubConfig *cfg, const char *image,
+ 		entry->skip = 1;
+ }
+ 
+-void setDefaultImage(struct grubConfig *config, int hasNew,
+-		     const char *defaultKernelPath, int newIsDefault,
+-		     const char *prefix, int flags, int index)
++void setDefaultImage(struct grubConfig *config, int isUserSpecifiedKernelPath,
++		     const char *defaultKernelPath, int newBootEntryIsDefault,
++		     const char *prefix, int flags, int newDefaultBootEntryIndex)
+ {
+ 	struct singleEntry *entry, *entry2, *newDefault;
+ 	int i, j;
+ 
+-	if (newIsDefault) {
++	if (newBootEntryIsDefault) {
+ 		config->defaultImage = 0;
+ 		return;
+-	} else if ((index >= 0) && config->cfi->defaultIsIndex) {
+-		if (findEntryByIndex(config, index))
+-			config->defaultImage = index;
++	} else if ((newDefaultBootEntryIndex >= 0) && config->cfi->defaultIsIndex) {
++		if (findEntryByIndex(config, newDefaultBootEntryIndex))
++			config->defaultImage = newDefaultBootEntryIndex;
+ 		else
+ 			config->defaultImage = -1;
+ 		return;
+@@ -2531,7 +2531,7 @@ void setDefaultImage(struct grubConfig *config, int hasNew,
+ 
+ 	if (entry && !entry->skip) {
+ 		/* we can preserve the default */
+-		if (hasNew)
++		if (isUserSpecifiedKernelPath)
+ 			config->defaultImage++;
+ 
+ 		/* count the number of entries erased before this one */
+@@ -2540,7 +2540,7 @@ void setDefaultImage(struct grubConfig *config, int hasNew,
+ 			if (entry2->skip)
+ 				config->defaultImage--;
+ 		}
+-	} else if (hasNew) {
++	} else if (isUserSpecifiedKernelPath) {
+ 		config->defaultImage = 0;
+ 	} else {
+ 		/* Either we just erased the default (or the default line was
+-- 
+2.17.1
+
diff --git a/SOURCES/0031-Add-index-constant-definitions-instead-of-open-coded.patch b/SOURCES/0031-Add-index-constant-definitions-instead-of-open-coded.patch
new file mode 100644
index 0000000..079cc3b
--- /dev/null
+++ b/SOURCES/0031-Add-index-constant-definitions-instead-of-open-coded.patch
@@ -0,0 +1,198 @@
+From 624a75f2d01d986ec78f60319ebc2acd37faada2 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 13 Dec 2016 14:36:31 -0500
+Subject: [PATCH 31/55] Add index constant definitions instead of open-coded
+ values.
+
+Added numeric constants NO_DEFAULT_ENTRY and FIRST_ENTRY_INDEX. This
+clarifies the intent of various assignment operations throughout the
+source file.
+
+Related: rhbz#1285601
+---
+ grubby.c | 44 ++++++++++++++++++++++++--------------------
+ 1 file changed, 24 insertions(+), 20 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 9af8d17b345..a717c18999b 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -132,6 +132,10 @@ struct singleEntry {
+ #define NEED_DEVTREE (1 << 6)
+ 
+ #define MAIN_DEFAULT	    (1 << 0)
++#define FIRST_ENTRY_INDEX    0	/* boot entry index value begin and increment
++				   from this initial value */
++#define NO_DEFAULT_ENTRY    -1	/* indicates that no specific default boot
++				   entry was set or currently exists */
+ #define DEFAULT_SAVED       -2
+ #define DEFAULT_SAVED_GRUB2 -3
+ 
+@@ -1612,7 +1616,7 @@ static struct grubConfig *readConfig(const char *inName,
+ 						*end == ' ' || *end == '\t'))
+ 					end++;
+ 				if (*end)
+-					cfg->defaultImage = -1;
++					cfg->defaultImage = NO_DEFAULT_ENTRY;
+ 			} else if (defaultLine->numElements == 3) {
+ 				char *value = defaultLine->elements[2].item;
+ 				while (*value && (*value == '"' ||
+@@ -1625,7 +1629,7 @@ static struct grubConfig *readConfig(const char *inName,
+ 						*end == ' ' || *end == '\t'))
+ 					end++;
+ 				if (*end)
+-					cfg->defaultImage = -1;
++					cfg->defaultImage = NO_DEFAULT_ENTRY;
+ 			}
+ 		} else if (cfi->defaultSupportSaved &&
+ 			   !strncmp(defaultLine->elements[1].item, "saved",
+@@ -1635,7 +1639,7 @@ static struct grubConfig *readConfig(const char *inName,
+ 			cfg->defaultImage =
+ 			    strtol(defaultLine->elements[1].item, &end, 10);
+ 			if (*end)
+-				cfg->defaultImage = -1;
++				cfg->defaultImage = NO_DEFAULT_ENTRY;
+ 		} else if (defaultLine->numElements >= 2) {
+ 			int i = 0;
+ 			while ((entry = findEntryByIndex(cfg, i))) {
+@@ -1663,7 +1667,7 @@ static struct grubConfig *readConfig(const char *inName,
+ 			if (entry) {
+ 				cfg->defaultImage = i;
+ 			} else {
+-				cfg->defaultImage = -1;
++				cfg->defaultImage = NO_DEFAULT_ENTRY;
+ 			}
+ 		}
+ 	} else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
+@@ -1680,7 +1684,7 @@ static struct grubConfig *readConfig(const char *inName,
+ 				cfg->defaultImage = index;
+ 		}
+ 	} else {
+-		cfg->defaultImage = 0;
++		cfg->defaultImage = FIRST_ENTRY_INDEX;
+ 	}
+ 
+ 	return cfg;
+@@ -1700,7 +1704,7 @@ static void writeDefault(FILE * out, char *indent,
+ 		fprintf(out, "%sdefault%ssaved\n", indent, separator);
+ 	else if (cfg->cfi->defaultIsSaved) {
+ 		fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
+-		if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
++		if (cfg->defaultImage >= FIRST_ENTRY_INDEX && cfg->cfi->setEnv) {
+ 			char *title;
+ 			entry = findEntryByIndex(cfg, cfg->defaultImage);
+ 			line = getLineByType(LT_MENUENTRY, entry->lines);
+@@ -1713,7 +1717,7 @@ static void writeDefault(FILE * out, char *indent,
+ 							 "saved_entry", title);
+ 			}
+ 		}
+-	} else if (cfg->defaultImage > -1) {
++	} else if (cfg->defaultImage >= FIRST_ENTRY_INDEX) {
+ 		if (cfg->cfi->defaultIsIndex) {
+ 			if (cfg->cfi->defaultIsVariable) {
+ 				fprintf(out, "%sset default=\"%d\"\n", indent,
+@@ -2417,7 +2421,7 @@ struct singleEntry *findTemplate(struct grubConfig *cfg, const char *prefix,
+ 				}
+ 			}
+ 		}
+-	} else if (cfg->defaultImage > -1) {
++	} else if (cfg->defaultImage >= FIRST_ENTRY_INDEX) {
+ 		entry = findEntryByIndex(cfg, cfg->defaultImage);
+ 		if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
+ 			if (indexPtr)
+@@ -2499,20 +2503,20 @@ void setDefaultImage(struct grubConfig *config, int isUserSpecifiedKernelPath,
+ 	int i, j;
+ 
+ 	if (newBootEntryIsDefault) {
+-		config->defaultImage = 0;
++		config->defaultImage = FIRST_ENTRY_INDEX;
+ 		return;
+ 	} else if ((newDefaultBootEntryIndex >= 0) && config->cfi->defaultIsIndex) {
+ 		if (findEntryByIndex(config, newDefaultBootEntryIndex))
+ 			config->defaultImage = newDefaultBootEntryIndex;
+ 		else
+-			config->defaultImage = -1;
++			config->defaultImage = NO_DEFAULT_ENTRY;
+ 		return;
+ 	} else if (defaultKernelPath) {
+ 		i = 0;
+ 		if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
+ 			config->defaultImage = i;
+ 		} else {
+-			config->defaultImage = -1;
++			config->defaultImage = NO_DEFAULT_ENTRY;
+ 			return;
+ 		}
+ 	}
+@@ -2524,7 +2528,7 @@ void setDefaultImage(struct grubConfig *config, int isUserSpecifiedKernelPath,
+ 		/* default is set to saved, we don't want to change it */
+ 		return;
+ 
+-	if (config->defaultImage > -1)
++	if (config->defaultImage >= FIRST_ENTRY_INDEX)
+ 		entry = findEntryByIndex(config, config->defaultImage);
+ 	else
+ 		entry = NULL;
+@@ -2541,7 +2545,7 @@ void setDefaultImage(struct grubConfig *config, int isUserSpecifiedKernelPath,
+ 				config->defaultImage--;
+ 		}
+ 	} else if (isUserSpecifiedKernelPath) {
+-		config->defaultImage = 0;
++		config->defaultImage = FIRST_ENTRY_INDEX;
+ 	} else {
+ 		/* Either we just erased the default (or the default line was
+ 		 * bad to begin with) and didn't put a new one in. We'll use
+@@ -2550,7 +2554,7 @@ void setDefaultImage(struct grubConfig *config, int isUserSpecifiedKernelPath,
+ 		    findTemplate(config, prefix, &config->defaultImage, 1,
+ 				 flags);
+ 		if (!newDefault)
+-			config->defaultImage = -1;
++			config->defaultImage = NO_DEFAULT_ENTRY;
+ 	}
+ }
+ 
+@@ -5175,11 +5179,11 @@ int main(int argc, const char **argv)
+ 		struct singleEntry *entry;
+ 		char *rootspec;
+ 
+-		if (config->defaultImage == -1)
++		if (config->defaultImage == NO_DEFAULT_ENTRY)
+ 			return 0;
+ 		if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
+ 		    cfi->defaultIsSaved)
+-			config->defaultImage = 0;
++			config->defaultImage = FIRST_ENTRY_INDEX;
+ 		entry = findEntryByIndex(config, config->defaultImage);
+ 		if (!entry)
+ 			return 0;
+@@ -5202,11 +5206,11 @@ int main(int argc, const char **argv)
+ 		struct singleLine *line;
+ 		struct singleEntry *entry;
+ 
+-		if (config->defaultImage == -1)
++		if (config->defaultImage == NO_DEFAULT_ENTRY)
+ 			return 0;
+ 		if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
+ 		    cfi->defaultIsSaved)
+-			config->defaultImage = 0;
++			config->defaultImage = FIRST_ENTRY_INDEX;
+ 		entry = findEntryByIndex(config, config->defaultImage);
+ 		if (!entry)
+ 			return 0;
+@@ -5236,11 +5240,11 @@ int main(int argc, const char **argv)
+ 		return 0;
+ 
+ 	} else if (displayDefaultIndex) {
+-		if (config->defaultImage == -1)
++		if (config->defaultImage == NO_DEFAULT_ENTRY)
+ 			return 0;
+ 		if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
+ 		    cfi->defaultIsSaved)
+-			config->defaultImage = 0;
++			config->defaultImage = FIRST_ENTRY_INDEX;
+ 		printf("%i\n", config->defaultImage);
+ 		return 0;
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0032-Track-configuration-modifications.patch b/SOURCES/0032-Track-configuration-modifications.patch
new file mode 100644
index 0000000..ad3a653
--- /dev/null
+++ b/SOURCES/0032-Track-configuration-modifications.patch
@@ -0,0 +1,50 @@
+From 12ae8096bd3099b81fded8c30be1a8050ed7e68c Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 8 Dec 2016 16:52:45 -0500
+Subject: [PATCH 32/55] Track configuration modifications
+
+The setDefaultImage function had a subtle dependency on being run before
+addNewKernel is invoked. Added the ability to track invocation to
+prevent them from being so tightly coupled.
+
+Related: rhbz#1285601
+---
+ grubby.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/grubby.c b/grubby.c
+index a717c18999b..1f712ec1391 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -678,6 +678,8 @@ struct grubConfig {
+ 	int fallbackImage;	/* just like defaultImage */
+ 	int flags;
+ 	struct configFileInfo *cfi;
++	int isModified;		/* assumes only one entry added
++				   per invocation of grubby */
+ };
+ 
+ blkid_cache blkid;
+@@ -1297,6 +1299,7 @@ static struct grubConfig *readConfig(const char *inName,
+ 	cfg->theLines = NULL;
+ 	cfg->entries = NULL;
+ 	cfg->fallbackImage = 0;
++	cfg->isModified = 0;
+ 
+ 	/* copy everything we have */
+ 	while (*head) {
+@@ -4726,8 +4729,10 @@ int addNewKernel(struct grubConfig *config, struct singleEntry *template,
+ 	}
+ 
+ 	if (updateImage(config, indexs, prefix, newKernelArgs, NULL,
+-			newMBKernelArgs, NULL))
++			newMBKernelArgs, NULL)) {
++		config->isModified = 1;
+ 		return 1;
++	}
+ 
+ 	return 0;
+ }
+-- 
+2.17.1
+
diff --git a/SOURCES/0033-Fix-some-test-cases-where-the-resulting-default-inde.patch b/SOURCES/0033-Fix-some-test-cases-where-the-resulting-default-inde.patch
new file mode 100644
index 0000000..de85989
--- /dev/null
+++ b/SOURCES/0033-Fix-some-test-cases-where-the-resulting-default-inde.patch
@@ -0,0 +1,65 @@
+From 5ec8c855f307a89f08013c832bd7e121c8f83327 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 15 Dec 2016 21:47:28 -0500
+Subject: [PATCH 33/55] Fix some test cases where the resulting default index
+ is wrong
+
+Fix two issues with tests where removing a kernel or adding a boot entry
+at a user specified index had the wrong default index selected in the
+expected output.
+
+One of these issues is the --set-index test cases for grub 1, which
+expect --make-default is implied where it should not be.
+
+The third is a removal test, where the default index in the result data
+is off by one when we've removed 2 entries keyed off of the kernel
+filesystem path.
+
+This change causes these test cases to fail.
+
+Resolves: rhbz#1285601
+---
+ test/results/add/g1.17   | 2 +-
+ test/results/add/g1.9    | 2 +-
+ test/results/remove/g7.1 | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/test/results/add/g1.17 b/test/results/add/g1.17
+index 6a388228768..eda4e93329d 100644
+--- a/test/results/add/g1.17
++++ b/test/results/add/g1.17
+@@ -7,7 +7,7 @@
+ #          kernel /vmlinuz-version ro root=/dev/sda1
+ #          initrd /initrd-version.img
+ #boot=/dev/hda
+-default=1
++default=0
+ timeout=10
+ splashimage=(hd0,0)/grub/splash.xpm.gz
+ title Red Hat Linux (2.4.7-2)
+diff --git a/test/results/add/g1.9 b/test/results/add/g1.9
+index 310623d13d2..8976e762d74 100644
+--- a/test/results/add/g1.9
++++ b/test/results/add/g1.9
+@@ -7,7 +7,7 @@
+ #          kernel /vmlinuz-version ro root=/dev/sda1
+ #          initrd /initrd-version.img
+ #boot=/dev/hda
+-default=2
++default=1
+ timeout=10
+ splashimage=(hd0,0)/grub/splash.xpm.gz
+ title Red Hat Linux (2.4.7-2)
+diff --git a/test/results/remove/g7.1 b/test/results/remove/g7.1
+index ea1a6fbaec9..611d7a16685 100644
+--- a/test/results/remove/g7.1
++++ b/test/results/remove/g7.1
+@@ -1,4 +1,4 @@
+-default=1
++default=0
+ timeout=10
+ splashimage=(hd0,5)/boot/grub/splash.xpm.gz
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0034-Don-t-assume-make-default-just-because-set-index-was.patch b/SOURCES/0034-Don-t-assume-make-default-just-because-set-index-was.patch
new file mode 100644
index 0000000..2bfdd6b
--- /dev/null
+++ b/SOURCES/0034-Don-t-assume-make-default-just-because-set-index-was.patch
@@ -0,0 +1,197 @@
+From ff38bf8209faf54c25e15b1fcec4184fee1f39e9 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 13 Dec 2016 18:20:15 -0500
+Subject: [PATCH 34/55] Don't assume --make-default just because --set-index
+ was passed.
+
+grubby previously made the assumption that every time a new
+boot entry gets added using --set-index, it should be the default. Due
+to this behavior, it also masked an logic error that prevented the
+selection of the proper index in cases where it was necessary to
+dynamically pick a new default boot entry, or to keep the existing
+default boot entry when its position in the config file moved.
+
+Resolves: rhbz#1285601
+---
+ grubby.c | 138 ++++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 97 insertions(+), 41 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 1f712ec1391..fcca6364887 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -2498,66 +2498,121 @@ void markRemovedImage(struct grubConfig *cfg, const char *image,
+ 		entry->skip = 1;
+ }
+ 
+-void setDefaultImage(struct grubConfig *config, int isUserSpecifiedKernelPath,
++void setDefaultImage(struct grubConfig *config, int isAddingBootEntry,
+ 		     const char *defaultKernelPath, int newBootEntryIsDefault,
+-		     const char *prefix, int flags, int newDefaultBootEntryIndex)
++		     const char *prefix, int flags,
++		     int newDefaultBootEntryIndex, int newBootEntryIndex)
+ {
+-	struct singleEntry *entry, *entry2, *newDefault;
+-	int i, j;
++	struct singleEntry *bootEntry, *newDefault;
++	int indexToVerify, firstKernelEntryIndex, currentLookupIndex;
+ 
++	/* handle the two cases where the user explictly picks the default
++	 * boot entry index as it would exist post-modification */
++
++	/* Case 1: user chose to make the latest boot entry the default */
+ 	if (newBootEntryIsDefault) {
+-		config->defaultImage = FIRST_ENTRY_INDEX;
++		config->defaultImage = newBootEntryIndex;
+ 		return;
+-	} else if ((newDefaultBootEntryIndex >= 0) && config->cfi->defaultIsIndex) {
+-		if (findEntryByIndex(config, newDefaultBootEntryIndex))
++	}
++
++	/* Case 2: user picked an arbitrary index as the default boot entry */
++	if (newDefaultBootEntryIndex >= FIRST_ENTRY_INDEX
++	    && config->cfi->defaultIsIndex) {
++		indexToVerify = newDefaultBootEntryIndex;
++
++		/* user chose to make latest boot entry the default */
++		if (newDefaultBootEntryIndex == newBootEntryIndex) {
++			config->defaultImage = newBootEntryIndex;
++			return;
++		}
++
++		/* the user picks the default index based on the
++		 * order of the bootloader configuration after
++		 * modification; ensure we are checking for the
++		 * existence of the correct entry */
++		if (newBootEntryIndex < newDefaultBootEntryIndex) {
++			if (!config->isModified)
++				indexToVerify--;
++		}
++
++		/* verify the user selected index will exist */
++		if (findEntryByIndex(config, indexToVerify)) {
+ 			config->defaultImage = newDefaultBootEntryIndex;
+-		else
+-			config->defaultImage = NO_DEFAULT_ENTRY;
+-		return;
+-	} else if (defaultKernelPath) {
+-		i = 0;
+-		if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
+-			config->defaultImage = i;
+ 		} else {
+ 			config->defaultImage = NO_DEFAULT_ENTRY;
+-			return;
+ 		}
+-	}
+ 
+-	/* defaultImage now points to what we'd like to use, but before any
+-	 * order changes */
+-	if ((config->defaultImage == DEFAULT_SAVED) ||
+-	    (config->defaultImage == DEFAULT_SAVED_GRUB2))
+-		/* default is set to saved, we don't want to change it */
+ 		return;
++	}
+ 
+-	if (config->defaultImage >= FIRST_ENTRY_INDEX)
+-		entry = findEntryByIndex(config, config->defaultImage);
+-	else
+-		entry = NULL;
++	/* handle cases where the index value may shift */
+ 
+-	if (entry && !entry->skip) {
+-		/* we can preserve the default */
+-		if (isUserSpecifiedKernelPath)
++	/* check validity of existing default or first-entry-found
++	   selection */
++	if (defaultKernelPath) {
++		/* user requested first-entry-found */
++		if (!findEntryByPath(config, defaultKernelPath,
++				     prefix, &firstKernelEntryIndex)) {
++			/* don't change default if can't find match */
++			config->defaultImage = NO_DEFAULT_ENTRY;
++			return;
++		}
++
++		config->defaultImage = firstKernelEntryIndex;
++
++		/* this is where we start looking for decrement later */
++		currentLookupIndex = config->defaultImage;
++
++		if (isAddingBootEntry && !config->isModified &&
++		    (newBootEntryIndex < config->defaultImage)) {
++			/* increment because new entry added before default */
+ 			config->defaultImage++;
+-
+-		/* count the number of entries erased before this one */
+-		for (j = 0; j < config->defaultImage; j++) {
+-			entry2 = findEntryByIndex(config, j);
+-			if (entry2->skip)
+-				config->defaultImage--;
+ 		}
+-	} else if (isUserSpecifiedKernelPath) {
+-		config->defaultImage = FIRST_ENTRY_INDEX;
+ 	} else {
+-		/* Either we just erased the default (or the default line was
+-		 * bad to begin with) and didn't put a new one in. We'll use
+-		 * the first valid image. */
++		/* use pre-existing default entry */
++		currentLookupIndex = config->defaultImage;
++
++		if (isAddingBootEntry
++		    && (newBootEntryIndex <= config->defaultImage)) {
++			config->defaultImage++;
++
++			if (config->isModified) {
++				currentLookupIndex++;
++			}
++		}
++	}
++
++	/* sanity check - is this entry index valid? */
++	bootEntry = findEntryByIndex(config, currentLookupIndex);
++
++	if ((bootEntry && bootEntry->skip) || !bootEntry) {
++		/* entry is to be skipped or is invalid */
++		if (isAddingBootEntry) {
++			config->defaultImage = newBootEntryIndex;
++			return;
++		}
+ 		newDefault =
+ 		    findTemplate(config, prefix, &config->defaultImage, 1,
+ 				 flags);
+-		if (!newDefault)
++		if (!newDefault) {
+ 			config->defaultImage = NO_DEFAULT_ENTRY;
++		}
++
++		return;
++	}
++
++	currentLookupIndex--;
++
++	/* decrement index by the total number of entries deleted */
++
++	for (indexToVerify = currentLookupIndex;
++	     indexToVerify >= FIRST_ENTRY_INDEX; indexToVerify--) {
++
++		bootEntry = findEntryByIndex(config, indexToVerify);
++
++		if (bootEntry && bootEntry->skip) {
++			config->defaultImage--;
++		}
+ 	}
+ }
+ 
+@@ -5265,7 +5320,8 @@ int main(int argc, const char **argv)
+ 	markRemovedImage(config, removeKernelPath, bootPrefix);
+ 	markRemovedImage(config, removeMBKernel, bootPrefix);
+ 	setDefaultImage(config, newKernelPath != NULL, defaultKernel,
+-			makeDefault, bootPrefix, flags, defaultIndex);
++			makeDefault, bootPrefix, flags, defaultIndex,
++			newIndex);
+ 	setFallbackImage(config, newKernelPath != NULL);
+ 	if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
+ 			removeArgs, newMBKernelArgs, removeMBKernelArgs))
+-- 
+2.17.1
+
diff --git a/SOURCES/0035-Clarify-set-default-index-in-the-man-page.patch b/SOURCES/0035-Clarify-set-default-index-in-the-man-page.patch
new file mode 100644
index 0000000..6d22110
--- /dev/null
+++ b/SOURCES/0035-Clarify-set-default-index-in-the-man-page.patch
@@ -0,0 +1,32 @@
+From 8836f04b716c9ca56b518627c3d8064f18f9c33d Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 15 Dec 2016 21:53:31 -0500
+Subject: [PATCH 35/55] Clarify --set-default-index in the man page.
+
+This changes the man page to say that the index value provided with
+--set-default-index applies to the boot entry list after modifications.
+
+Resolves: rhbz#1285601
+---
+ grubby.8 | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grubby.8 b/grubby.8
+index fdf2766fe9a..1e8f140c4df 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -144,8 +144,9 @@ boot entry. This may not be invoked with \fB-\-set-default-index\fR.
+ 
+ .TP
+ \fB-\-set-default-index\fR=\fIentry-index\fR
+-Makes the given entry number the default boot entry. This may not
+-be invoked with \fB-\-set-default\fR.
++Makes the given entry number the default boot entry. This may not be invoked
++with \fB-\-set-default\fR.  The given value represents the index in the
++post-modification boot entry list.
+ 
+ .TP
+ \fB-\-make-default\fR
+-- 
+2.17.1
+
diff --git a/SOURCES/0036-Add-multi-entry-removal-test-1285601.patch b/SOURCES/0036-Add-multi-entry-removal-test-1285601.patch
new file mode 100644
index 0000000..43eb777
--- /dev/null
+++ b/SOURCES/0036-Add-multi-entry-removal-test-1285601.patch
@@ -0,0 +1,261 @@
+From 2d19bc931b0b2a70abc18f6d15dddbf547cafd94 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 22 Dec 2016 17:40:52 -0500
+Subject: [PATCH 36/55] Add multi-entry removal test (#1285601)
+
+Test what happens to the default entry set in the grub environment after
+removing the first two boot entries.
+
+Related: rhbz#1285601
+---
+ test.sh                            |   7 ++
+ test/grub2-support_files/grubenv.4 |   3 +
+ test/grub2.19                      | 112 +++++++++++++++++++++++++++++
+ test/results/remove/g2.19          |  88 +++++++++++++++++++++++
+ 4 files changed, 210 insertions(+)
+ create mode 100644 test/grub2-support_files/grubenv.4
+ create mode 100644 test/grub2.19
+ create mode 100644 test/results/remove/g2.19
+
+diff --git a/test.sh b/test.sh
+index fb7cd2381d5..1ef9eca535d 100755
+--- a/test.sh
++++ b/test.sh
+@@ -565,6 +565,13 @@ if [ "$testgrub2" == "y" ]; then
+         --copy-default --title 'Red Hat Enterprise Linux Server' \
+         --args=root=/dev/mapper/foo--
+ 
++    grub2Test grub2.19 remove/g2.19 --env grubenv.4 \
++        --remove-kernel=/boot/vmlinuz-2.6.38.2-9.fc15.x86_64 \
++        --boot-filesystem=/boot/
++    commandTest "saved_default output" \
++        "grub2-editenv test/grub2-support_files/env_temp list" \
++        "saved_entry=Linux, with Fedora 2.6.38.8-32.fc15.x86_64"
++
+     # copy a stanza and add arguments as well, while using --set-index=
+     testing="GRUB2 add stanza and new args with --set-index="
+     grub2Test grub2.18 add/g2-1.18  --env grubenv.3 \
+diff --git a/test/grub2-support_files/grubenv.4 b/test/grub2-support_files/grubenv.4
+new file mode 100644
+index 00000000000..13116382feb
+--- /dev/null
++++ b/test/grub2-support_files/grubenv.4
+@@ -0,0 +1,3 @@
++# GRUB Environment Block
++saved_entry=Linux, with Fedora 2.6.38.8-32.fc15.x86_64
++################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################
+diff --git a/test/grub2.19 b/test/grub2.19
+new file mode 100644
+index 00000000000..be07b3ea6b3
+--- /dev/null
++++ b/test/grub2.19
+@@ -0,0 +1,112 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  insmod vbe
++  insmod vga
++  insmod video_bochs
++  insmod video_cirrus
++}
++
++set timeout=5
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'First Title To Remove' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod part_msdos
++	insmod ext2
++	set root='(hd0,msdos1)'
++	search --no-floppy --fs-uuid --set=root df0170c9-7d05-415c-bbd1-d4d503ba0eed
++	echo	'Loading Linux 2.6.38.2-9.fc15.x86_64 ...'
++	linux	/vmlinuz-2.6.38.2-9.fc15.x86_64 root=/dev/mapper/vg_pjones5-lv_root ro quiet rhgb
++	echo	'Loading initial ramdisk ...'
++	initrd	/initramfs-2.6.38.2-9.fc15.x86_64.img
++}
++menuentry 'Second Title To Remove' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod part_msdos
++	insmod ext2
++	set root='(hd0,msdos1)'
++	search --no-floppy --fs-uuid --set=root df0170c9-7d05-415c-bbd1-d4d503ba0eed
++	echo	'Loading Linux 2.6.38.2-9.fc15.x86_64 ...'
++	linux	/vmlinuz-2.6.38.2-9.fc15.x86_64 root=/dev/mapper/vg_pjones5-lv_root ro quiet rhgb
++	echo	'Loading initial ramdisk ...'
++	initrd	/initramfs-2.6.38.2-9.fc15.x86_64.img
++}
++menuentry 'Linux, with Fedora 2.6.38.8-32.fc15.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod part_msdos
++	insmod ext2
++	set root='(hd0,msdos1)'
++	search --no-floppy --fs-uuid --set=root df0170c9-7d05-415c-bbd1-d4d503ba0eed
++	echo	'Loading Fedora 2.6.38.8-32.fc15.x86_64 ...'
++	linux	/vmlinuz-2.6.38.8-32.fc15.x86_64 root=/dev/mapper/vg_pjones5-lv_root ro quiet rhgb
++	echo	'Loading initial ramdisk ...'
++	initrd	/initramfs-2.6.38.8-32.fc15.x86_64.img
++}
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
++
++### BEGIN /etc/grub.d/90_persistent ###
++### END /etc/grub.d/90_persistent ###
+diff --git a/test/results/remove/g2.19 b/test/results/remove/g2.19
+new file mode 100644
+index 00000000000..f65edd5ac29
+--- /dev/null
++++ b/test/results/remove/g2.19
+@@ -0,0 +1,88 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  insmod vbe
++  insmod vga
++  insmod video_bochs
++  insmod video_cirrus
++}
++
++set timeout=5
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Linux, with Fedora 2.6.38.8-32.fc15.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod part_msdos
++	insmod ext2
++	set root='(hd0,msdos1)'
++	search --no-floppy --fs-uuid --set=root df0170c9-7d05-415c-bbd1-d4d503ba0eed
++	echo	'Loading Fedora 2.6.38.8-32.fc15.x86_64 ...'
++	linux	/vmlinuz-2.6.38.8-32.fc15.x86_64 root=/dev/mapper/vg_pjones5-lv_root ro quiet rhgb
++	echo	'Loading initial ramdisk ...'
++	initrd	/initramfs-2.6.38.8-32.fc15.x86_64.img
++}
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
++
++### BEGIN /etc/grub.d/90_persistent ###
++### END /etc/grub.d/90_persistent ###
+-- 
+2.17.1
+
diff --git a/SOURCES/0037-Fix-findTemplate-index-logic-1285601.patch b/SOURCES/0037-Fix-findTemplate-index-logic-1285601.patch
new file mode 100644
index 0000000..ba378b5
--- /dev/null
+++ b/SOURCES/0037-Fix-findTemplate-index-logic-1285601.patch
@@ -0,0 +1,40 @@
+From 46843e71656264d98ceda79985e5d341a8d58aa7 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 22 Dec 2016 17:52:14 -0500
+Subject: [PATCH 37/55] Fix findTemplate index logic (#1285601)
+
+The fallback case where findTemplate has to look for the first entry
+contained a logic flaw that could return an incorrect index. This
+discovered index should be reduced by one for each boot entry that will
+be skipped in the final output. The flaw occurred because the index
+variable was used for the loop upper bound at the same time as it was
+being decremented within the actual loop body. The loop would thus fail
+to examine a number of boot entries equal to the total number of
+iterations the loop performed.
+
+Related: rhbz#1285601
+---
+ grubby.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index fcca6364887..692c351ccb6 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -2436,8 +2436,11 @@ struct singleEntry *findTemplate(struct grubConfig *cfg, const char *prefix,
+ 	index = 0;
+ 	while ((entry = findEntryByIndex(cfg, index))) {
+ 		if (suitableImage(entry, prefix, skipRemoved, flags)) {
+-			int j;
+-			for (j = 0; j < index; j++) {
++			int j, unmodifiedIndex;
++
++			unmodifiedIndex = index;
++
++			for (j = 0; j < unmodifiedIndex; j++) {
+ 				entry2 = findEntryByIndex(cfg, j);
+ 				if (entry2->skip)
+ 					index--;
+-- 
+2.17.1
+
diff --git a/SOURCES/0038-Write-correct-default-to-environment-1285601.patch b/SOURCES/0038-Write-correct-default-to-environment-1285601.patch
new file mode 100644
index 0000000..2e3a959
--- /dev/null
+++ b/SOURCES/0038-Write-correct-default-to-environment-1285601.patch
@@ -0,0 +1,43 @@
+From d3c64808b6fc4794e2c58b1812315914966afea9 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 22 Dec 2016 17:56:44 -0500
+Subject: [PATCH 38/55] Write correct default to environment (#1285601)
+
+grubby writes the title of the default boot entry to the bootloader
+environment. The title lookup did not correctly account for the offset
+required if some boot entries were marked for removal.
+
+Related: rhbz#1285601
+---
+ grubby.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/grubby.c b/grubby.c
+index 692c351ccb6..9edb26d0ded 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -1709,7 +1709,20 @@ static void writeDefault(FILE * out, char *indent,
+ 		fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
+ 		if (cfg->defaultImage >= FIRST_ENTRY_INDEX && cfg->cfi->setEnv) {
+ 			char *title;
+-			entry = findEntryByIndex(cfg, cfg->defaultImage);
++			int trueIndex, currentIndex;
++
++			trueIndex = 0;
++			currentIndex = 0;
++
++			while ((entry = findEntryByIndex(cfg, currentIndex))) {
++				if (!entry->skip) {
++					if (trueIndex == cfg->defaultImage) {
++						break;
++					}
++					trueIndex++;
++				}
++				currentIndex++;
++			}
+ 			line = getLineByType(LT_MENUENTRY, entry->lines);
+ 			if (!line)
+ 				line = getLineByType(LT_TITLE, entry->lines);
+-- 
+2.17.1
+
diff --git a/SOURCES/0039-Initialize-variable-for-ppc-environment-1285601.patch b/SOURCES/0039-Initialize-variable-for-ppc-environment-1285601.patch
new file mode 100644
index 0000000..1030e38
--- /dev/null
+++ b/SOURCES/0039-Initialize-variable-for-ppc-environment-1285601.patch
@@ -0,0 +1,29 @@
+From d124974021199ddee0d1af1b2c7866f533c2f23a Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Mon, 27 Feb 2017 15:59:53 -0500
+Subject: [PATCH 39/55] Initialize variable for ppc environment (#1285601)
+
+Building on PPC does not default the value of an uninitialized integer
+to zero which caused test failures.
+
+Related: rhbz#1285601
+---
+ grubby.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grubby.c b/grubby.c
+index 9edb26d0ded..9ccad2735dd 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -2566,6 +2566,8 @@ void setDefaultImage(struct grubConfig *config, int isAddingBootEntry,
+ 	/* check validity of existing default or first-entry-found
+ 	   selection */
+ 	if (defaultKernelPath) {
++                /* we must initialize this */
++                firstKernelEntryIndex = 0;
+ 		/* user requested first-entry-found */
+ 		if (!findEntryByPath(config, defaultKernelPath,
+ 				     prefix, &firstKernelEntryIndex)) {
+-- 
+2.17.1
+
diff --git a/SOURCES/0040-Fix-initial-saved_entry-read-issue-1285601.patch b/SOURCES/0040-Fix-initial-saved_entry-read-issue-1285601.patch
new file mode 100644
index 0000000..e1590a8
--- /dev/null
+++ b/SOURCES/0040-Fix-initial-saved_entry-read-issue-1285601.patch
@@ -0,0 +1,64 @@
+From a8367596ca63156509eed0b332a077247765b811 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 28 Feb 2017 18:31:56 -0500
+Subject: [PATCH 40/55] Fix initial saved_entry read issue (#1285601)
+
+If a system has never had a kernel upgrade/rollback then grubby
+does not read saved_entry properly.  Added a guard to catch
+saved_entry and read it to pick the proper index in these cases.
+
+Resolves: rhbz#1285601
+---
+ grubby.c | 29 +++++++++++++++++++++++++++--
+ 1 file changed, 27 insertions(+), 2 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 9ccad2735dd..974b81c7864 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -2522,6 +2522,9 @@ void setDefaultImage(struct grubConfig *config, int isAddingBootEntry,
+ 	struct singleEntry *bootEntry, *newDefault;
+ 	int indexToVerify, firstKernelEntryIndex, currentLookupIndex;
+ 
++        /* initialize */
++        currentLookupIndex = FIRST_ENTRY_INDEX;
++
+ 	/* handle the two cases where the user explictly picks the default
+ 	 * boot entry index as it would exist post-modification */
+ 
+@@ -2587,8 +2590,30 @@ void setDefaultImage(struct grubConfig *config, int isAddingBootEntry,
+ 			config->defaultImage++;
+ 		}
+ 	} else {
+-		/* use pre-existing default entry */
+-		currentLookupIndex = config->defaultImage;
++                /* check to see if the default is stored in the environment */
++                if (config->defaultImage < FIRST_ENTRY_INDEX) {
++                    if (config->defaultImage == DEFAULT_SAVED || config->defaultImage == DEFAULT_SAVED_GRUB2)
++                    {
++                        if (config->cfi->defaultIsSaved) {
++                            if (config->cfi->getEnv) {
++                                char *defaultTitle = config->cfi->getEnv(config->cfi, "saved_entry");
++
++                                if (defaultTitle) {
++                                    if (isnumber(defaultTitle)) {
++                                        currentLookupIndex = atoi(defaultTitle);
++                                    } else {
++                                        findEntryByTitle(config, defaultTitle, &currentLookupIndex);
++                                    }
++                                    /* set the default Image to an actual index */
++                                    config->defaultImage = currentLookupIndex;
++                                }
++                            }
++                         }
++                    }
++                } else {
++                        /* use pre-existing default entry from the file*/
++                        currentLookupIndex = config->defaultImage;
++                }
+ 
+ 		if (isAddingBootEntry
+ 		    && (newBootEntryIndex <= config->defaultImage)) {
+-- 
+2.17.1
+
diff --git a/SOURCES/0041-Add-s390-s390x-info-test-1285601.patch b/SOURCES/0041-Add-s390-s390x-info-test-1285601.patch
new file mode 100644
index 0000000..0988f81
--- /dev/null
+++ b/SOURCES/0041-Add-s390-s390x-info-test-1285601.patch
@@ -0,0 +1,74 @@
+From 4d48c517db42b6d7f30d7d2441863704bd01eb11 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 14 Mar 2017 22:55:27 -0400
+Subject: [PATCH 41/55] Add s390/s390x --info test (#1285601)
+
+Running the --info grubby option on s390/s390x platforms always returned
+the (null) value. Added a test to look at --info and ensure it comes out
+as a user would expect.
+
+Resolves: rhbz#1285601
+---
+ test.sh                |  2 ++
+ test/results/info/z2.1 |  6 ++++++
+ test/zipl.2            | 22 ++++++++++++++++++++++
+ 3 files changed, 30 insertions(+)
+ create mode 100644 test/results/info/z2.1
+ create mode 100644 test/zipl.2
+
+diff --git a/test.sh b/test.sh
+index 1ef9eca535d..afa4f705b2b 100755
+--- a/test.sh
++++ b/test.sh
+@@ -320,6 +320,8 @@ testing="Z/IPL display default title"
+ ziplDisplayTest zipl.1 defaulttitle/z.1 --default-title
+ testing="Z/IPL display default kernel"
+ ziplDisplayTest zipl.1 defaultkernel/z.1 --default-kernel
++testing="Z/IPL display entry information"
++ziplDisplayTest zipl.2 info/z2.1 --info=1
+ 
+ testing="GRUB fallback directive"
+ grubTest grub.5 fallback/g5.1 --remove-kernel=/boot/vmlinuz-2.4.7-ac3 \
+diff --git a/test/results/info/z2.1 b/test/results/info/z2.1
+new file mode 100644
+index 00000000000..e5ce3a1a61f
+--- /dev/null
++++ b/test/results/info/z2.1
+@@ -0,0 +1,6 @@
++index=1
++kernel=/boot/vmlinuz-3.10.0-514.6.2.el7.s390x
++args="crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0 LANG=en_US.UTF-8 systemd.log_level=debug systemd.log_target=kmsg"
++root=/dev/mapper/rhel_ibm--z--68-root
++initrd=/boot/initramfs-3.10.0-514.6.2.el7.s390x.img
++title=3.10.0-514.6.2.el7.s390x_with_debugging
+diff --git a/test/zipl.2 b/test/zipl.2
+new file mode 100644
+index 00000000000..f064b2a36d5
+--- /dev/null
++++ b/test/zipl.2
+@@ -0,0 +1,22 @@
++[defaultboot]
++defaultauto
++prompt=1
++timeout=5
++default=3.10.0-514.6.2.el7.s390x_with_debugging
++target=/boot
++[3.10.0-514.6.2.el7.s390x]
++	image=/boot/vmlinuz-3.10.0-514.6.2.el7.s390x
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0 LANG=en_US.UTF-8"
++	ramdisk=/boot/initramfs-3.10.0-514.6.2.el7.s390x.img
++[3.10.0-514.6.2.el7.s390x_with_debugging]
++	image=/boot/vmlinuz-3.10.0-514.6.2.el7.s390x
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0 LANG=en_US.UTF-8 systemd.log_level=debug systemd.log_target=kmsg"
++	ramdisk=/boot/initramfs-3.10.0-514.6.2.el7.s390x.img
++[linux]
++	image=/boot/vmlinuz-3.10.0-514.el7.s390x
++	ramdisk=/boot/initramfs-3.10.0-514.el7.s390x.img
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0 LANG=en_US.UTF-8"
++[linux-0-rescue-196fd0394b7442a6838686745f03fd04]
++	image=/boot/vmlinuz-0-rescue-196fd0394b7442a6838686745f03fd04
++	ramdisk=/boot/initramfs-0-rescue-196fd0394b7442a6838686745f03fd04.img
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0"
+-- 
+2.17.1
+
diff --git a/SOURCES/0042-Fix-info-for-s390x-s390-1285601.patch b/SOURCES/0042-Fix-info-for-s390x-s390-1285601.patch
new file mode 100644
index 0000000..58744c4
--- /dev/null
+++ b/SOURCES/0042-Fix-info-for-s390x-s390-1285601.patch
@@ -0,0 +1,59 @@
+From 8d81aeffcb1c2f9706dfe625a2f9f5e61f8a5c63 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 14 Mar 2017 15:20:53 -0400
+Subject: [PATCH 42/55] Fix --info for s390x/s390 (#1285601)
+
+The --info flag for grubby on s390/s390x always returned (null). Fixed
+codepath to use extractTitle where necessary and get the actual title.
+
+Related: rhbz#1285601
+---
+ grubby.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 974b81c7864..9bf051dfed4 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -2684,7 +2684,7 @@ void setFallbackImage(struct grubConfig *config, int hasNew)
+ 	}
+ }
+ 
+-void displayEntry(struct singleEntry *entry, const char *prefix, int index)
++void displayEntry(struct grubConfig *config, struct singleEntry *entry, const char *prefix, int index)
+ {
+ 	struct singleLine *line;
+ 	char *root = NULL;
+@@ -2780,7 +2780,14 @@ void displayEntry(struct singleEntry *entry, const char *prefix, int index)
+ 
+ 	line = getLineByType(LT_TITLE, entry->lines);
+ 	if (line) {
+-		printf("title=%s\n", line->elements[1].item);
++                char *entryTitle;
++                /* if we can extractTitle, then it's a zipl config and
++                 * if not then we go ahead with what's existed prior */
++                entryTitle = extractTitle(config, line);
++                if (!entryTitle) {
++                    entryTitle=line->elements[1].item;
++                }
++		printf("title=%s\n", entryTitle);
+ 	} else {
+ 		char *title;
+ 		line = getLineByType(LT_MENUENTRY, entry->lines);
+@@ -3196,11 +3203,11 @@ int displayInfo(struct grubConfig *config, char *kernel, const char *prefix)
+ 			printf("lba\n");
+ 	}
+ 
+-	displayEntry(entry, prefix, i);
++	displayEntry(config, entry, prefix, i);
+ 
+ 	i++;
+ 	while ((entry = findEntryByPath(config, kernel, prefix, &i))) {
+-		displayEntry(entry, prefix, i);
++		displayEntry(config, entry, prefix, i);
+ 		i++;
+ 	}
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0043-Add-s390-s390x-set-default-index-test-1285601.patch b/SOURCES/0043-Add-s390-s390x-set-default-index-test-1285601.patch
new file mode 100644
index 0000000..9d1b63c
--- /dev/null
+++ b/SOURCES/0043-Add-s390-s390x-set-default-index-test-1285601.patch
@@ -0,0 +1,59 @@
+From 6d2322507be50c828c400a6de0cd48bf30dfa1b1 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 14 Mar 2017 22:39:20 -0400
+Subject: [PATCH 43/55] Add s390/s390x set-default-index test (#1285601)
+
+Adds a test to ensure set-default-index actually works for s390 and
+s390x platforms.
+
+Related: rhbz#1285601
+---
+ test.sh                   |  2 ++
+ test/results/default/z2.1 | 22 ++++++++++++++++++++++
+ 2 files changed, 24 insertions(+)
+ create mode 100644 test/results/default/z2.1
+
+diff --git a/test.sh b/test.sh
+index afa4f705b2b..aaa6e9323a6 100755
+--- a/test.sh
++++ b/test.sh
+@@ -314,6 +314,8 @@ liloDisplayTest lilo.1 defaultkernel/l1.1 --default-kernel
+ testing="Z/IPL default directive"
+ ziplTest zipl.1 default/z1.1 --add-kernel /boot/new-kernel --title test
+ ziplTest zipl.1 default/z1.2 --add-kernel /boot/new-kernel --title test --make-default
++testing="Z/IPL default index directive"
++ziplTest zipl.2 default/z2.1 --set-default-index=0
+ testing="Z/IPL display default index"
+ ziplDisplayTest zipl.1 defaultindex/0 --default-index
+ testing="Z/IPL display default title"
+diff --git a/test/results/default/z2.1 b/test/results/default/z2.1
+new file mode 100644
+index 00000000000..93e7491e00a
+--- /dev/null
++++ b/test/results/default/z2.1
+@@ -0,0 +1,22 @@
++[defaultboot]
++defaultauto
++prompt=1
++timeout=5
++default=3.10.0-514.6.2.el7.s390x
++target=/boot
++[3.10.0-514.6.2.el7.s390x]
++	image=/boot/vmlinuz-3.10.0-514.6.2.el7.s390x
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0 LANG=en_US.UTF-8"
++	ramdisk=/boot/initramfs-3.10.0-514.6.2.el7.s390x.img
++[3.10.0-514.6.2.el7.s390x_with_debugging]
++	image=/boot/vmlinuz-3.10.0-514.6.2.el7.s390x
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0 LANG=en_US.UTF-8 systemd.log_level=debug systemd.log_target=kmsg"
++	ramdisk=/boot/initramfs-3.10.0-514.6.2.el7.s390x.img
++[linux]
++	image=/boot/vmlinuz-3.10.0-514.el7.s390x
++	ramdisk=/boot/initramfs-3.10.0-514.el7.s390x.img
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0 LANG=en_US.UTF-8"
++[linux-0-rescue-196fd0394b7442a6838686745f03fd04]
++	image=/boot/vmlinuz-0-rescue-196fd0394b7442a6838686745f03fd04
++	ramdisk=/boot/initramfs-0-rescue-196fd0394b7442a6838686745f03fd04.img
++	parameters="root=/dev/mapper/rhel_ibm--z--68-root crashkernel=auto rd.dasd=0.0.0120 rd.dasd=0.0.0121 rd.dasd=0.0.0122 rd.dasd=0.0.0123 rd.lvm.lv=rhel_ibm-z-68/root rd.lvm.lv=rhel_ibm-z-68/swap rd.znet=qeth,0.0.8000,0.0.8001,0.0.8002,layer2=1,portname=z-68,portno=0"
+-- 
+2.17.1
+
diff --git a/SOURCES/0044-Fix-setDefaultImage-for-s390-s390x-1285601.patch b/SOURCES/0044-Fix-setDefaultImage-for-s390-s390x-1285601.patch
new file mode 100644
index 0000000..be8938d
--- /dev/null
+++ b/SOURCES/0044-Fix-setDefaultImage-for-s390-s390x-1285601.patch
@@ -0,0 +1,32 @@
+From 9b6266cdec60130435e9ba61af855e370ec31f1a Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 14 Mar 2017 22:25:02 -0400
+Subject: [PATCH 44/55] Fix setDefaultImage for s390/s390x (#1285601)
+
+The setDefaultImage routine has never actually supported s390/s390x when
+picking an arbitrary index because a zipl config never has the property
+defaultIsIndex set to 1. Eliminating the extraneous check resolved the
+issue on s390/s390x and does not appear to break other platforms.
+
+Related: rhbz#1285601
+---
+ grubby.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 9bf051dfed4..5202485a541 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -2535,8 +2535,7 @@ void setDefaultImage(struct grubConfig *config, int isAddingBootEntry,
+ 	}
+ 
+ 	/* Case 2: user picked an arbitrary index as the default boot entry */
+-	if (newDefaultBootEntryIndex >= FIRST_ENTRY_INDEX
+-	    && config->cfi->defaultIsIndex) {
++	if (newDefaultBootEntryIndex >= FIRST_ENTRY_INDEX) {
+ 		indexToVerify = newDefaultBootEntryIndex;
+ 
+ 		/* user chose to make latest boot entry the default */
+-- 
+2.17.1
+
diff --git a/SOURCES/0045-Be-more-thorough-about-flushing-our-config-file-when.patch b/SOURCES/0045-Be-more-thorough-about-flushing-our-config-file-when.patch
new file mode 100644
index 0000000..f675e14
--- /dev/null
+++ b/SOURCES/0045-Be-more-thorough-about-flushing-our-config-file-when.patch
@@ -0,0 +1,78 @@
+From 7d48cb09b85b81f707565db6d35b1ba0d247b6b4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fcami@fedoraproject.org>
+Date: Fri, 23 Jun 2017 23:56:50 +0200
+Subject: [PATCH 45/55] Be more thorough about flushing our config file when
+ writing.
+
+Add missing fclose() at the end of writeConfig
+Use fflush(out) + fsync(fileno(out) on temporary file
+fsync() the destination directory after rename
+---
+ grubby.c | 41 ++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 34 insertions(+), 7 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 5202485a541..11ee64a02b9 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -1789,6 +1789,7 @@ static int writeConfig(struct grubConfig *cfg, char *outName,
+ 	int needs = MAIN_DEFAULT;
+ 	struct stat sb;
+ 	int i;
++	int rc = 0;
+ 
+ 	if (!strcmp(outName, "-")) {
+ 		out = stdout;
+@@ -1903,16 +1904,42 @@ static int writeConfig(struct grubConfig *cfg, char *outName,
+ 	}
+ 
+ 	if (tmpOutName) {
+-		if (rename(tmpOutName, outName)) {
++		/* write userspace buffers */
++		if (fflush(out))
++			rc = 1;
++
++		/* purge the write-back cache with fsync() */
++		if (fsync(fileno(out)))
++			rc = 1;
++
++		if (fclose(out))
++			rc = 1;
++
++		if (rc == 0 && rename(tmpOutName, outName)) {
++			unlink(tmpOutName);
++			rc = 1;
++		}
++
++		/* fsync() the destination directory after rename */
++		if (rc == 0) {
++			int dirfd;
++
++			dirfd = open(dirname(strdupa(outName)), O_RDONLY);
++			if (dirfd < 0)
++				rc = 1;
++			else if (fsync(dirfd))
++				rc = 1;
++
++			if (dirfd >= 0)
++				close(dirfd);
++		}
++
++		if (rc == 1)
+ 			fprintf(stderr,
+-				_("grubby: error moving %s to %s: %s\n"),
+-				tmpOutName, outName, strerror(errno));
+-			unlink(outName);
+-			return 1;
+-		}
++				_("grubby: error flushing data: %m\n"));
+ 	}
+ 
+-	return 0;
++	return rc;
+ }
+ 
+ static int numEntries(struct grubConfig *cfg)
+-- 
+2.17.1
+
diff --git a/SOURCES/0046-Fix-incorrect-test-case-and-remove-args-with-a-value.patch b/SOURCES/0046-Fix-incorrect-test-case-and-remove-args-with-a-value.patch
new file mode 100644
index 0000000..fbf91c8
--- /dev/null
+++ b/SOURCES/0046-Fix-incorrect-test-case-and-remove-args-with-a-value.patch
@@ -0,0 +1,168 @@
+From 92d22c7cb9a100a601b9a28cb78b8fbde9dac9a8 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 27 Sep 2017 11:28:00 -0400
+Subject: [PATCH 46/55] Fix incorrect test case and --remove-args with a value.
+
+Currently we have this test case:
+
+  grubTest grub.3 updargs/g3.4 --update-kernel=ALL --remove-args="hdd=foobar"
+
+This fails to notice that the actual argument in grub.3 is hdd=ide-scsi,
+and removes it anyway, and the data in g3.4 supports that behavior.
+This is clearly wrong, and so this patch introduces updargs/g3.5, which
+leaves hdd=ide-scsi intact, and fixes the code so that it won't modify
+the command line in that case.
+
+Resolves: rhbz#1476273
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c                  | 71 ++++++++++++++++++++++++++++++++-------
+ test.sh                   |  2 +-
+ test/results/updargs/g3.5 | 16 +++++++++
+ 3 files changed, 76 insertions(+), 13 deletions(-)
+ create mode 100644 test/results/updargs/g3.5
+
+diff --git a/grubby.c b/grubby.c
+index 11ee64a02b9..9af04dea01b 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -3563,23 +3563,67 @@ static void removeElement(struct singleLine *line, int removeHere)
+ 	line->numElements--;
+ }
+ 
+-int argMatch(const char *one, const char *two)
++static int argNameMatch(const char *one, const char *two)
+ {
+ 	char *first, *second;
++	char *chptra, *chptrb;
++	int rc;
++
++	first = strcpy(alloca(strlen(one) + 1), one);
++	second = strcpy(alloca(strlen(two) + 1), two);
++
++	chptra = strchr(first, '=');
++	if (chptra)
++		*chptra = '\0';
++
++	chptrb = strchr(second, '=');
++	if (chptrb)
++		*chptrb = '\0';
++
++	rc = strcmp(first, second);
++
++	if (chptra)
++		*chptra = '=';
++	if (chptrb)
++		*chptrb = '=';
++
++	return rc;
++}
++
++static int argHasValue(const char *arg)
++{
+ 	char *chptr;
+ 
++	chptr = strchr(arg, '=');
++	if (chptr)
++		return 1;
++	return 0;
++}
++
++static int argValueMatch(const char *one, const char *two)
++{
++	char *first, *second;
++	char *chptra, *chptrb;
++
+ 	first = strcpy(alloca(strlen(one) + 1), one);
+ 	second = strcpy(alloca(strlen(two) + 1), two);
+ 
+-	chptr = strchr(first, '=');
+-	if (chptr)
+-		*chptr = '\0';
++	chptra = strchr(first, '=');
++	if (chptra)
++		chptra += 1;
+ 
+-	chptr = strchr(second, '=');
+-	if (chptr)
+-		*chptr = '\0';
++	chptrb = strchr(second, '=');
++	if (chptrb)
++		chptrb += 1;
+ 
+-	return strcmp(first, second);
++	if (!chptra && !chptrb)
++		return 0;
++	else if (!chptra)
++		return *chptrb - 0;
++	else if (!chptrb)
++		return 0 - *chptra;
++	else
++		return strcmp(chptra, chptrb);
+ }
+ 
+ int updateActualImage(struct grubConfig *cfg, const char *image,
+@@ -3723,7 +3767,7 @@ int updateActualImage(struct grubConfig *cfg, const char *image,
+ 				}
+ 				if (usedElements[i])
+ 					continue;
+-				if (!argMatch(line->elements[i].item, *arg)) {
++				if (!argNameMatch(line->elements[i].item, *arg)) {
+ 					usedElements[i] = 1;
+ 					break;
+ 				}
+@@ -3782,9 +3826,12 @@ int updateActualImage(struct grubConfig *cfg, const char *image,
+ 				    !strcmp(line->elements[i].item, "--"))
+ 					/* reached the end of hyper args, stop here */
+ 					break;
+-				if (!argMatch(line->elements[i].item, *arg)) {
+-					removeElement(line, i);
+-					break;
++				if (!argNameMatch(line->elements[i].item, *arg)) {
++					if (!argHasValue(*arg) ||
++					    !argValueMatch(line->elements[i].item, *arg)) {
++						removeElement(line, i);
++						break;
++					}
+ 				}
+ 			}
+ 			/* handle removing LT_ROOT line too */
+diff --git a/test.sh b/test.sh
+index aaa6e9323a6..a97ada94d22 100755
+--- a/test.sh
++++ b/test.sh
+@@ -386,7 +386,7 @@ grubTest grub.3 updargs/g3.2 --update-kernel=DEFAULT \
+     --args "root=/dev/hdd1 hdd=notide-scsi"
+ grubTest grub.3 updargs/g3.4 --update-kernel=ALL --remove-args="hdd"
+ grubTest grub.3 updargs/g3.4 --update-kernel=ALL --remove-args="hdd=ide-scsi"
+-grubTest grub.3 updargs/g3.4 --update-kernel=ALL --remove-args="hdd=foobar"
++grubTest grub.3 updargs/g3.5 --update-kernel=ALL --remove-args="hdd=foobar"
+ grubTest grub.3 updargs/g3.7 --update-kernel=ALL \
+     --remove-args="hdd root ro"
+ grubTest grub.7 updargs/g7.2 --boot-filesystem=/    \
+diff --git a/test/results/updargs/g3.5 b/test/results/updargs/g3.5
+new file mode 100644
+index 00000000000..7d50bb87d84
+--- /dev/null
++++ b/test/results/updargs/g3.5
+@@ -0,0 +1,16 @@
++#boot=/dev/hda
++timeout=10
++splashimage=(hd0,1)/grub/splash.xpm.gz
++title Red Hat Linux (2.4.7-2smp)
++	root (hd0,1)
++	kernel /vmlinuz-2.4.7-2smp ro root=/dev/hda5 hdd=ide-scsi
++	initrd /initrd-2.4.7-2smp.img
++title Red Hat Linux-up (2.4.7-2)
++	root (hd0,1)
++	kernel /vmlinuz-2.4.7-2 ro root=/dev/hda5 hdd=ide-scsi
++	initrd /initrd-2.4.7-2.img
++title DOS
++	rootnoverify (hd0,0)
++	chainloader +1
++
++
+-- 
+2.17.1
+
diff --git a/SOURCES/0047-grubby-Make-sure-configure-BOOTLOADER-variables-are-.patch b/SOURCES/0047-grubby-Make-sure-configure-BOOTLOADER-variables-are-.patch
new file mode 100644
index 0000000..0408c1a
--- /dev/null
+++ b/SOURCES/0047-grubby-Make-sure-configure-BOOTLOADER-variables-are-.patch
@@ -0,0 +1,59 @@
+From 19b47a3eab1b4fc490e007caaa9597595f15f496 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 31 Jan 2018 13:06:48 -0500
+Subject: [PATCH 47/55] grubby: Make sure configure$BOOTLOADER variables are
+ set correctly.
+
+When we've chosen a bootloader because it's default for a platform, and
+we've already determined it's not overridden by the command line, set
+the configure$BOOTLOADER variable to 1 so that our checks for which
+bootloader are selected work correctly.
+
+Resolves: rhbz#1340893
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grubby.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 9af04dea01b..c1b4104892c 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -5151,22 +5151,27 @@ int main(int argc, const char **argv)
+ 	if (!cfi) {
+ 		if (grub2FindConfig(&grub2ConfigType)) {
+ 			cfi = &grub2ConfigType;
++			configureGrub2 = 1;
+ 			if (envPath)
+ 				cfi->envFile = envPath;
+-		} else
++		} else {
+ #ifdef __ia64__
+ 			cfi = &eliloConfigType;
+-#elif __powerpc__
++			configureLilo = 1;
++#elif defined(__powerpc__)
+ 			cfi = &yabootConfigType;
+-#elif __sparc__
++			configureYaboot = 1;
++#elif defined(__sparc__)
+ 			cfi = &siloConfigType;
+-#elif __s390__
++			configureSilo = 1;
++#elif defined(__s390__) || defined(__s390x__)
+ 			cfi = &ziplConfigType;
+-#elif __s390x__
+-			cfi = &ziplConfigtype;
++			configureZipl = 1;
+ #else
+ 			cfi = &grubConfigType;
++			configureGrub = 1;
+ #endif
++		}
+ 	}
+ 
+ 	if (!grubConfig) {
+-- 
+2.17.1
+
diff --git a/SOURCES/0048-remove-the-old-crufty-u-boot-support.patch b/SOURCES/0048-remove-the-old-crufty-u-boot-support.patch
new file mode 100644
index 0000000..dbbd1d8
--- /dev/null
+++ b/SOURCES/0048-remove-the-old-crufty-u-boot-support.patch
@@ -0,0 +1,237 @@
+From 7a09f286922ab14df7a07e50d81e197bedd6d20d Mon Sep 17 00:00:00 2001
+From: Dennis Gilmore <dennis@ausil.us>
+Date: Wed, 30 Aug 2017 14:03:45 -0500
+Subject: [PATCH 48/55] remove the old crufty u-boot support
+
+Fedora has only supported extlinux.conf for a few releases now
+as a result it should be the only way we boot systems. Remove
+the no longer needed uboot file
+
+Signed-off-by: Dennis Gilmore <dennis@ausil.us>
+---
+ new-kernel-pkg | 116 -------------------------------------------------
+ uboot          |  43 ------------------
+ 2 files changed, 159 deletions(-)
+ delete mode 100644 uboot
+
+diff --git a/new-kernel-pkg b/new-kernel-pkg
+index 64225deb06b..0fe6caab51a 100755
+--- a/new-kernel-pkg
++++ b/new-kernel-pkg
+@@ -37,7 +37,6 @@ else
+ fi
+ 
+ [ -f /etc/sysconfig/kernel ] && . /etc/sysconfig/kernel
+-[ -f /etc/sysconfig/uboot ] && . /etc/sysconfig/uboot
+ 
+ cfgGrub2=""
+ cfgGrub2Efi=""
+@@ -50,7 +49,6 @@ grubConfig=""
+ grub2Config=""
+ grub2EfiConfig=""
+ extlinuxConfig=""
+-ubootScript="/boot/boot.scr"
+ 
+ ARCH=$(uname -m)
+ 
+@@ -84,13 +82,6 @@ elif [[ ${ARCH} =~ armv[5|7].*l ]] ; then
+     liloConfig=""
+     bootPrefix=/boot
+     extlinuxConfig=$(readlink -f /etc/extlinux.conf 2>/dev/null)
+-    ubootDir=${UBOOT_DIR:-"/boot"}
+-    ubootScript=$ubootDir/${UBOOT_SCR:-"boot.scr"}
+-    ubootKList=${UBOOT_KLIST:-"klist.txt"}
+-    ubootDevice=/dev/${UBOOT_DEVICE:-"mmcblk0p1"}
+-    ubootDefaultImage=${UBOOT_UIMAGE:-"uImage"}
+-    ubootDefaultInitrd=${UBOOT_UINITRD:-"uInitrd"}
+-    ubootAddress=${UBOOT_IMGADDR:-"0x00008000"}
+     mounted=""
+     liloFlag=""
+     isx86=""
+@@ -386,53 +377,6 @@ remove() {
+ 	[ -n "$verbose" ] && echo "$liloConfig does not exist, not running grubby"
+     fi
+ 
+-    if [ -n "$cfguBoot" ]; then
+-	[ -n "$verbose" ] && echo "removing $version from $ubootDir..."
+-
+-	if [ -f $ubootDir/$ubootKList ]; then
+-	    tmpKList=`mktemp $ubootDir/$ubootKList.XXXX`
+-	    curversion=`tail -n1 $ubootDir/$ubootKList`
+-	    sed "/$version$/d" $ubootDir/$ubootKList > $tmpKList
+-	    newversion=`tail -n1 $tmpKList`
+-	    if [ -f $ubootDir/uImage-$newversion ] && [ -f $ubootDir/uInitrd-$newversion ]; then
+-		if [ "$curversion" != "$newversion" ]; then
+-		    cp -fp $ubootDir/uImage-$newversion $ubootDir/${ubootDefaultImage}
+-		    if [ $? -ne 0 ]; then
+-			[ -n "$verbose" ] && echo "copy uImage-$newversion error, default kernel not replaced!" && exit
+-		    fi
+-		    cp -fp $ubootDir/uInitrd-$newversion $ubootDir/${ubootDefaultInitrd}
+-		    if [ $? -ne 0 ]; then
+-			[ -n "$verbose" ] && echo "copy uInitrd-$newversion error, default Initrd not replaced!" && exit
+-		    fi
+-		fi
+-
+-		[ -n "$verbose" ] && echo "removing uImage-$version"
+-		if [ -f $ubootDir/uImage-$version ]; then
+-		    rm -f $ubootDir/uImage-$version
+-		else
+-		    [ -n "$verbose" ] && echo "uImage-$version did not exist!"
+-		fi
+-
+-		[ -n "$verbose" ] && echo "removing uInitrd-$version"
+-		if [ -f $ubootDir/uInitrd-$version ]; then
+-		    rm -f $ubootDir/uInitrd-$version
+-		else
+-		    [ -n "$verbose" ] && echo "uInitrd-$version did not exist!"
+-		fi
+-
+-		mv $tmpKList $ubootDir/$ubootKList
+-		[ -x /sbin/a-b-c ] && /sbin/a-b-c
+-	    else
+-		[ -n "$verbose" ] && echo "uImage $newversion does not exist!"
+-		[ -f $tmpKList ] && rm -f $tmpKList
+-	    fi
+-        else
+-            [ -n "$verbose" ] && echo "No previous kernel version.  U-Boot images not removed!"
+-        fi
+-    else
+-	[ -n "$verbose" ] && echo "$ubootScript does not exist, not modifying $ubootDir"
+-    fi
+-
+     if [ -n "$cfgExtlinux" ]; then
+ 	[ -n "$verbose" ] && echo "removing $version from $extlinuxConfig"
+ 	$grubby --extlinux -c $extlinuxConfig \
+@@ -534,36 +478,6 @@ update() {
+ 	[ -n "$verbose" ] && echo "$liloConfig does not exist, not running grubby"
+     fi
+ 
+-    if [ -n "$cfguBoot" ]; then
+-	[ -n "$verbose" ] && echo "adding $version to $ubootDir..."
+-
+-	[ -n "$verbose" ] && echo "creating uImage-$version"
+-	mkimage -A arm -O linux -T kernel -C none -a $ubootAddress \
+-		-e $ubootAddress -n $version \
+-		-d $kernelImage $ubootDir/uImage-$version
+-
+-	[ -n "$verbose" ] && echo "creating uInitrd-$version"
+-	mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 \
+-		-n initramfs -d $initrdfile $ubootDir/uInitrd-$version
+-
+-	if [ -f $ubootDir/uImage-$version ] && [ -f $ubootDir/uInitrd-$version ]; then
+-	    cp -fp $ubootDir/uImage-$version $ubootDir/${ubootDefaultImage}
+-	    if [ $? -ne 0 ]; then
+-		[ -n "$verbose" ] && echo "copy uImage-$version error, kernel not installed!" && exit
+-	    fi
+-	    cp -fp $ubootDir/uInitrd-$version $ubootDir/${ubootDefaultInitrd}
+-	    if [ $? -ne 0 ]; then
+-		[ -n "$verbose" ] && echo "copy uInitrd-$version error, kernel not installed!" && exit
+-	    fi
+-	    echo $version >> $ubootDir/$ubootKList
+-	    [ -x /sbin/a-b-c ] && /sbin/a-b-c
+-	else
+-	    [ -n "$verbose" ] && echo "cannot make $version the default"
+-	fi
+-    else
+-	[ -n "$verbose" ] && echo "$ubootScript does not exist, not setting up $ubootDir"
+-    fi
+-
+     if [ -n "$cfgExtlinux" ]; then
+ 	[ -n "$verbose" ] && echo "updating $version from $extlinuxConfig"
+ 	ARGS="--extlinux -c $extlinuxConfig --update-kernel=$kernelImage \
+@@ -874,33 +788,6 @@ fi
+ [ -n "$liloConfig" ] && [ -f "$liloConfig" ] && cfgLilo=1;
+ [ -n "$extlinuxConfig" ] && [ -f "$extlinuxConfig" ] && cfgExtlinux=1;
+ 
+-# if we have a U-Boot directory, but no boot script, check if the directory
+-# is mounted.  If not, mount it, and then check if a boot script exists.
+-if [ -n "$ubootDir" ]; then
+-    if [ -f "$ubootScript" ]; then
+-        cfguBoot=1
+-    else
+-	mountEntry=`mount | grep $ubootDir`
+-	if [ -z "$mountEntry" ]; then
+-	    mount $ubootDevice $ubootDir
+-	    mounted=1
+-	fi
+-	[ -f "$ubootScript" ] && cfguBoot=1;
+-    fi
+-fi
+-
+-# if we're using U-Boot, check if the default load address should change
+-if [ -n "$cfguBoot" -a -z "$UBOOT_IMGADDR" ]; then
+-    [[ $version  =~ .([^.]*)$ ]]
+-    platform=${BASH_REMATCH[1]}
+-    # A few platforms use an alternate kernel load address
+-    if [ "$platform" = "omap" ]; then
+-        ubootAddress=0x80008000
+-    elif [ "$platform" = "imx" ]; then
+-        ubootAddress=0x90008000
+-    fi
+-fi
+-
+ # if we have a lilo config on an x86 box, see if the default boot loader
+ # is lilo to determine if it should be run
+ if [ -n "$cfgLilo" -a -n "$isx86" ]; then
+@@ -917,9 +804,6 @@ elif [ "$mode" == "--rpmposttrans" ]; then
+     rpmposttrans
+ fi
+ 
+-# if we mounted the U-Boot directory, unmount it.
+-[ -n "$mounted" ] && umount $ubootDir
+-
+ # make sure changes make it to the disk.
+ # if /boot is a mountpoint, force the meta data on disk
+ # to by-pass writeback delay.
+diff --git a/uboot b/uboot
+deleted file mode 100644
+index 07d8671822f..00000000000
+--- a/uboot
++++ /dev/null
+@@ -1,43 +0,0 @@
+-# Settings for uBoot setup in /sbin/new-kernel-pkg
+-#
+-# Default values are provided below (as comments)
+-#
+-# WARNING: These values affect where grubby installs and removes
+-#          uBoot kernel images.  Changing these _after_ kernels have
+-#          been installed may cause removing a kernel image to fail.
+-
+-# directory where uBoot images and scripts are found
+-#UBOOT_DIR=/boot
+-
+-# Override the load address when running mkimage on the kernel.
+-# OMAP such as Beagleboard and Pandaboard: Use 0x80008000
+-# Tegra such as Trimslice: Use 0x00008000
+-# IMX such as Efika mx51 smarttop: Use 0x90008000
+-# Kirkwood such as Dreamplug, Guruplug, Sheevaplug: Use 0x00008000
+-# If left undefined grubby will use defults for Tegra or OMAP depending
+-# upon the contents of /proc/cpuinfo.
+-#UBOOT_IMGADDR=0x0x00008000
+-
+-# name of the text file containing the list of installed kernel versions
+-# NOTE: The versions are in order of installation.  The last entry should
+-#       always be the default boot kernel version.
+-#UBOOT_KLIST=klist.txt
+-
+-# device partition where uBoot images reside; mounted on $UBOOT_DIR
+-#UBOOT_DEVICE=mmcblk0p1
+-
+-
+-# NOTE: Both of the following files are automatically overwritte
+-#       when a kernel package is installed or removed.
+-
+-# default kernel uImage file name
+-#UBOOT_UIMAGE=uImage
+-
+-# default initrd uInitrd file name
+-#UBOOT_UINITRD=uInitrd
+-
+-# defualt for platform shipping an onboard dtb.
+-#SHIPSDTB=no
+-
+-# option to tell new-kernel-pkg a specific dtb file to load in extlinux.conf
+-#dtbfile=foo.dtb
+-- 
+2.17.1
+
diff --git a/SOURCES/0049-Change-return-type-in-getRootSpecifier.patch b/SOURCES/0049-Change-return-type-in-getRootSpecifier.patch
new file mode 100644
index 0000000..bc81fd3
--- /dev/null
+++ b/SOURCES/0049-Change-return-type-in-getRootSpecifier.patch
@@ -0,0 +1,148 @@
+From bd789c1aa159fb4992904e7c529789d7defbe332 Mon Sep 17 00:00:00 2001
+From: Nathaniel McCallum <npmccallum@redhat.com>
+Date: Fri, 2 Mar 2018 14:59:32 -0500
+Subject: [PATCH 49/55] Change return type in getRootSpecifier()
+
+Rather than returning a new allocation of the prefix, just return the
+length of the prefix. This change accomplishes a couple things. First,
+it reduces some memory leaks since the return value was often never
+freed.  Second, it simplifies the caller who is usually only interested
+in the length of the prefix.
+---
+ grubby.c | 57 ++++++++++++++++++++++++++------------------------------
+ 1 file changed, 26 insertions(+), 31 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index c1b4104892c..1fe850a3ddf 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -698,7 +698,7 @@ static int lineWrite(FILE * out, struct singleLine *line,
+ 		     struct configFileInfo *cfi);
+ static int getNextLine(char **bufPtr, struct singleLine *line,
+ 		       struct configFileInfo *cfi);
+-static char *getRootSpecifier(char *str);
++static size_t getRootSpecifier(const char *str);
+ static void requote(struct singleLine *line, struct configFileInfo *cfi);
+ static void insertElement(struct singleLine *line,
+ 			  const char *item, int insertHere,
+@@ -2122,7 +2122,7 @@ int suitableImage(struct singleEntry *entry, const char *bootPrefix,
+ 	char *fullName;
+ 	int i;
+ 	char *dev;
+-	char *rootspec;
++	size_t rs;
+ 	char *rootdev;
+ 
+ 	if (skipRemoved && entry->skip) {
+@@ -2150,12 +2150,11 @@ int suitableImage(struct singleEntry *entry, const char *bootPrefix,
+ 
+ 	fullName = alloca(strlen(bootPrefix) +
+ 			  strlen(line->elements[1].item) + 1);
+-	rootspec = getRootSpecifier(line->elements[1].item);
+-	int rootspec_offset = rootspec ? strlen(rootspec) : 0;
++	rs = getRootSpecifier(line->elements[1].item);
+ 	int hasslash = endswith(bootPrefix, '/') ||
+-	    beginswith(line->elements[1].item + rootspec_offset, '/');
++	    beginswith(line->elements[1].item + rs, '/');
+ 	sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
+-		line->elements[1].item + rootspec_offset);
++		line->elements[1].item + rs);
+ 	if (access(fullName, R_OK)) {
+ 		notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
+ 		return 0;
+@@ -2247,7 +2246,6 @@ struct singleEntry *findEntryByPath(struct grubConfig *config,
+ 	struct singleLine *line;
+ 	int i;
+ 	char *chptr;
+-	char *rootspec = NULL;
+ 	enum lineType_e checkType = LT_KERNEL;
+ 
+ 	if (isdigit(*kernel)) {
+@@ -2352,14 +2350,10 @@ struct singleEntry *findEntryByPath(struct grubConfig *config,
+ 
+ 				if (line && line->type != LT_MENUENTRY &&
+ 				    line->numElements >= 2) {
+-					rootspec =
+-					    getRootSpecifier(line->elements[1].
+-							     item);
+-					if (!strcmp
+-					    (line->elements[1].item +
+-					     ((rootspec !=
+-					       NULL) ? strlen(rootspec) : 0),
+-					     kernel + strlen(prefix)))
++					if (!strcmp(line->elements[1].item +
++						getRootSpecifier(
++							line->elements[1].item),
++						kernel + strlen(prefix)))
+ 						break;
+ 				}
+ 				if (line->type == LT_MENUENTRY &&
+@@ -3268,12 +3262,12 @@ struct singleLine *addLineTmpl(struct singleEntry *entry,
+ 		    type & (LT_HYPER | LT_KERNEL | LT_MBMODULE | LT_INITRD |
+ 			    LT_KERNEL_EFI | LT_INITRD_EFI | LT_KERNEL_16 |
+ 			    LT_INITRD_16)) {
+-			char *rootspec =
+-			    getRootSpecifier(tmplLine->elements[1].item);
+-			if (rootspec != NULL) {
++			size_t rs = getRootSpecifier(tmplLine->elements[1].item);
++			if (rs > 0) {
+ 				free(newLine->elements[1].item);
+-				newLine->elements[1].item =
+-				    sdupprintf("%s%s", rootspec, val);
++				newLine->elements[1].item = sdupprintf(
++					"%.*s%s", (int) rs,
++					tmplLine->elements[1].item, val);
+ 			}
+ 		}
+ 	}
+@@ -4325,17 +4319,19 @@ int checkForElilo(struct grubConfig *config)
+ 	return 1;
+ }
+ 
+-static char *getRootSpecifier(char *str)
++static size_t getRootSpecifier(const char *str)
+ {
+-	char *idx, *rootspec = NULL;
++	size_t rs = 0;
+ 
+ 	if (*str == '(') {
+-		idx = rootspec = strdup(str);
+-		while (*idx && (*idx != ')') && (!isspace(*idx)))
+-			idx++;
+-		*(++idx) = '\0';
++		for (; str[rs] != ')' && !isspace(str[rs]); rs++) {
++			if (!str[rs])
++				return rs;
++		}
++		rs++;
+ 	}
+-	return rootspec;
++
++	return rs;
+ }
+ 
+ static char *getInitrdVal(struct grubConfig *config,
+@@ -5365,7 +5361,7 @@ int main(int argc, const char **argv)
+ 	if (displayDefault) {
+ 		struct singleLine *line;
+ 		struct singleEntry *entry;
+-		char *rootspec;
++		size_t rs;
+ 
+ 		if (config->defaultImage == NO_DEFAULT_ENTRY)
+ 			return 0;
+@@ -5384,9 +5380,8 @@ int main(int argc, const char **argv)
+ 		if (!line)
+ 			return 0;
+ 
+-		rootspec = getRootSpecifier(line->elements[1].item);
+-		printf("%s%s\n", bootPrefix, line->elements[1].item +
+-		       ((rootspec != NULL) ? strlen(rootspec) : 0));
++		rs = getRootSpecifier(line->elements[1].item);
++		printf("%s%s\n", bootPrefix, line->elements[1].item + rs);
+ 
+ 		return 0;
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0050-Add-btrfs-subvolume-support-for-grub2.patch b/SOURCES/0050-Add-btrfs-subvolume-support-for-grub2.patch
new file mode 100644
index 0000000..25badc2
--- /dev/null
+++ b/SOURCES/0050-Add-btrfs-subvolume-support-for-grub2.patch
@@ -0,0 +1,208 @@
+From 9c6e5cd813d0c064e2805cdb4c6726d32b49d3e1 Mon Sep 17 00:00:00 2001
+From: Nathaniel McCallum <npmccallum@redhat.com>
+Date: Fri, 2 Mar 2018 08:40:18 -0500
+Subject: [PATCH 50/55] Add btrfs subvolume support for grub2
+
+In order to find the subvolume prefix from a given path, we parse
+/proc/mounts. In cases where /proc/mounts doesn't contain the
+filesystem, the caller can use the --mounts option to specify his own
+mounts file.
+
+Btrfs subvolumes are already supported by grub2 and by grub2-mkconfig.
+
+Fixes #22
+---
+ grubby.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 142 insertions(+), 4 deletions(-)
+
+diff --git a/grubby.c b/grubby.c
+index 1fe850a3ddf..396041a1187 100644
+--- a/grubby.c
++++ b/grubby.c
+@@ -68,6 +68,8 @@ int isEfi = 0;
+ 
+ char *saved_command_line = NULL;
+ 
++const char *mounts = "/proc/mounts";
++
+ /* comments get lumped in with indention */
+ struct lineElement {
+ 	char *item;
+@@ -2115,6 +2117,129 @@ static int endswith(const char *s, char c)
+ 	return s[slen] == c;
+ }
+ 
++typedef struct {
++	const char *start;
++	size_t      chars;
++} field;
++
++static int iscomma(int c)
++{
++	return c == ',';
++}
++
++static int isequal(int c)
++{
++	return c == '=';
++}
++
++static field findField(const field *in, typeof(isspace) *isdelim, field *out)
++{
++	field nxt = {};
++	size_t off = 0;
++
++	while (off < in->chars && isdelim(in->start[off]))
++		off++;
++
++	if (off == in->chars)
++		return nxt;
++
++	out->start = &in->start[off];
++	out->chars = 0;
++
++	while (off + out->chars < in->chars && !isdelim(out->start[out->chars]))
++		out->chars++;
++
++	nxt.start = out->start + out->chars;
++	nxt.chars = in->chars - off - out->chars;
++	return nxt;
++}
++
++static int fieldEquals(const field *in, const char *str)
++{
++	return in->chars == strlen(str) &&
++		strncmp(in->start, str, in->chars) == 0;
++}
++
++/* Parse /proc/mounts to determine the subvolume prefix. */
++static size_t subvolPrefix(const char *str)
++{
++	FILE *file = NULL;
++	char *line = NULL;
++	size_t prfx = 0;
++	size_t size = 0;
++
++	file = fopen(mounts, "r");
++	if (!file)
++		return 0;
++
++	for (ssize_t s; (s = getline(&line, &size, file)) >= 0; ) {
++		field nxt = { line, s };
++		field dev = {};
++		field path = {};
++		field type = {};
++		field opts = {};
++		field opt = {};
++
++		nxt = findField(&nxt, isspace, &dev);
++		if (!nxt.start)
++			continue;
++
++		nxt = findField(&nxt, isspace, &path);
++		if (!nxt.start)
++			continue;
++
++		nxt = findField(&nxt, isspace, &type);
++		if (!nxt.start)
++			continue;
++
++		nxt = findField(&nxt, isspace, &opts);
++		if (!nxt.start)
++			continue;
++
++		if (!fieldEquals(&type, "btrfs"))
++			continue;
++
++		/* We have found a btrfs mount point. */
++
++		nxt = opts;
++		while ((nxt = findField(&nxt, iscomma, &opt)).start) {
++			field key = {};
++			field val = {};
++
++			opt = findField(&opt, isequal, &key);
++			if (!opt.start)
++				continue;
++
++			opt = findField(&opt, isequal, &val);
++			if (!opt.start)
++				continue;
++
++			if (!fieldEquals(&key, "subvol"))
++				continue;
++
++			/* We have found a btrfs subvolume mount point. */
++
++			if (strncmp(val.start, str, val.chars))
++				continue;
++
++			if (val.start[val.chars - 1] != '/' &&
++				str[val.chars] != '/')
++				continue;
++
++			/* The subvolume mount point matches our input. */
++
++			if (prfx < val.chars)
++				prfx = val.chars;
++		}
++	}
++
++	dbgPrintf("%s(): str: '%s', prfx: '%s'\n", __FUNCTION__, str, prfx);
++
++	fclose(file);
++	free(line);
++	return prfx;
++}
++
+ int suitableImage(struct singleEntry *entry, const char *bootPrefix,
+ 		  int skipRemoved, int flags)
+ {
+@@ -3262,12 +3387,22 @@ struct singleLine *addLineTmpl(struct singleEntry *entry,
+ 		    type & (LT_HYPER | LT_KERNEL | LT_MBMODULE | LT_INITRD |
+ 			    LT_KERNEL_EFI | LT_INITRD_EFI | LT_KERNEL_16 |
+ 			    LT_INITRD_16)) {
+-			size_t rs = getRootSpecifier(tmplLine->elements[1].item);
++			const char *prfx = tmplLine->elements[1].item;
++			size_t rs = getRootSpecifier(prfx);
++			if (isinitrd(tmplLine->type)) {
++				for (struct singleLine *l = entry->lines;
++				     rs == 0 && l; l = l->next) {
++					if (iskernel(l->type)) {
++						prfx = l->elements[1].item;
++						rs = getRootSpecifier(prfx);
++						break;
++					}
++				}
++			}
+ 			if (rs > 0) {
+ 				free(newLine->elements[1].item);
+ 				newLine->elements[1].item = sdupprintf(
+-					"%.*s%s", (int) rs,
+-					tmplLine->elements[1].item, val);
++					"%.*s%s", (int) rs, prfx, val);
+ 			}
+ 		}
+ 	}
+@@ -4331,7 +4466,7 @@ static size_t getRootSpecifier(const char *str)
+ 		rs++;
+ 	}
+ 
+-	return rs;
++	return rs + subvolPrefix(str + rs);
+ }
+ 
+ static char *getInitrdVal(struct grubConfig *config,
+@@ -4963,6 +5098,9 @@ int main(int argc, const char **argv)
+ 		{"mbargs", 0, POPT_ARG_STRING, &newMBKernelArgs, 0,
+ 		 _("default arguments for the new multiboot kernel or "
+ 		   "new arguments for multiboot kernel being updated"), NULL},
++		{"mounts", 0, POPT_ARG_STRING, &mounts, 0,
++		 _("path to fake /proc/mounts file (for testing only)"),
++		 _("mounts")},
+ 		{"bad-image-okay", 0, 0, &badImageOkay, 0,
+ 		 _
+ 		 ("don't sanity check images in boot entries (for testing only)"),
+-- 
+2.17.1
+
diff --git a/SOURCES/0051-Add-tests-for-btrfs-support.patch b/SOURCES/0051-Add-tests-for-btrfs-support.patch
new file mode 100644
index 0000000..e50e01d
--- /dev/null
+++ b/SOURCES/0051-Add-tests-for-btrfs-support.patch
@@ -0,0 +1,1871 @@
+From e35dee09e4b7446651dfa5b231328e52ce4f8918 Mon Sep 17 00:00:00 2001
+From: Gene Czarcinski <gczarcinski@gmail.com>
+Date: Mon, 9 Jun 2014 21:11:37 -0400
+Subject: [PATCH 51/55] Add tests for btrfs support
+
+The tests performed are:
+- add kernel with /boot on btrfs subvol (20)
+- update kernel/add initrd with /boot on btrfs subvol (21)
+- add kernel with rootfs on btrfs subvol and /boot a directory (22)
+- update kernel/add initrd with rootfs on btrfs subvol and
+  /boot a directory (23)
+- add kernel and initrd with /boot on btrfs subvol (24)
+- add kernel and initrd with rootfs on btrfs subvol and /boot
+  a directory (25)
+---
+ test.sh                               |  40 +++++++
+ test/grub2-support_files/g2.20-mounts |   2 +
+ test/grub2-support_files/g2.21-mounts |   1 +
+ test/grub2-support_files/g2.22-mounts |   1 +
+ test/grub2-support_files/g2.23-mounts |   1 +
+ test/grub2-support_files/g2.24-mounts |   1 +
+ test/grub2-support_files/g2.25-mounts |   1 +
+ test/grub2.20                         | 126 ++++++++++++++++++++++
+ test/grub2.21                         | 140 +++++++++++++++++++++++++
+ test/grub2.22                         | 128 +++++++++++++++++++++++
+ test/grub2.23                         | 143 +++++++++++++++++++++++++
+ test/grub2.24                         | 126 ++++++++++++++++++++++
+ test/grub2.25                         | 128 +++++++++++++++++++++++
+ test/results/add/g2-1.20              | 140 +++++++++++++++++++++++++
+ test/results/add/g2-1.21              | 141 +++++++++++++++++++++++++
+ test/results/add/g2-1.22              | 143 +++++++++++++++++++++++++
+ test/results/add/g2-1.23              | 144 ++++++++++++++++++++++++++
+ test/results/add/g2-1.24              | 141 +++++++++++++++++++++++++
+ test/results/add/g2-1.25              | 144 ++++++++++++++++++++++++++
+ 19 files changed, 1691 insertions(+)
+ create mode 100644 test/grub2-support_files/g2.20-mounts
+ create mode 120000 test/grub2-support_files/g2.21-mounts
+ create mode 100644 test/grub2-support_files/g2.22-mounts
+ create mode 120000 test/grub2-support_files/g2.23-mounts
+ create mode 120000 test/grub2-support_files/g2.24-mounts
+ create mode 120000 test/grub2-support_files/g2.25-mounts
+ create mode 100644 test/grub2.20
+ create mode 100644 test/grub2.21
+ create mode 100644 test/grub2.22
+ create mode 100644 test/grub2.23
+ create mode 100644 test/grub2.24
+ create mode 100644 test/grub2.25
+ create mode 100644 test/results/add/g2-1.20
+ create mode 100644 test/results/add/g2-1.21
+ create mode 100644 test/results/add/g2-1.22
+ create mode 100644 test/results/add/g2-1.23
+ create mode 100644 test/results/add/g2-1.24
+ create mode 100644 test/results/add/g2-1.25
+
+diff --git a/test.sh b/test.sh
+index a97ada94d22..b3ba31e25ca 100755
+--- a/test.sh
++++ b/test.sh
+@@ -682,6 +682,46 @@ if [ "$testgrub2" == "y" ]; then
+             --initrd /boot/initramfs-0-rescue-5a94251776a14678911d4ae0949500f5.img \
+             --copy-default --title "Fedora 21 Rescue" --args=root=/fooooo \
+             --remove-kernel=wtf --boot-filesystem=/boot/
++
++        testing="GRUB2 add kernel with boot on btrfs subvol"
++        grub2Test grub2.20 add/g2-1.20 --add-kernel=/boot/new-kernel.img \
++            --title='title' \
++            --boot-filesystem=/boot/ \
++            --copy-default \
++            --mounts='test/grub2-support_files/g2.20-mounts'
++
++        testing="GRUB2 add initrd with boot on btrfs subvol"
++        grub2Test grub2.21 add/g2-1.21 --update-kernel=/boot/new-kernel.img \
++            --initrd=/boot/new-initrd --boot-filesystem=/boot/ \
++            --mounts='test/grub2-support_files/g2.21-mounts'
++
++        testing="GRUB2 add kernel with rootfs on btrfs subvol and boot directory"
++        grub2Test grub2.22 add/g2-1.22 --add-kernel=/boot/new-kernel.img \
++            --title='title' \
++            --boot-filesystem= \
++            --copy-default \
++            --mounts='test/grub2-support_files/g2.22-mounts'
++
++        testing="GRUB2 add initrd with rootfs on btrfs subvol and boot directory"
++        grub2Test grub2.23 add/g2-1.23 --update-kernel=/boot/new-kernel.img \
++            --initrd=/boot/new-initrd --boot-filesystem= \
++            --mounts='test/grub2-support_files/g2.23-mounts'
++
++        testing="GRUB2 add kernel and initrd with boot on btrfs subvol"
++        grub2Test grub2.24 add/g2-1.24 --add-kernel=/boot/new-kernel.img \
++            --title='title' \
++            --initrd=/boot/new-initrd \
++            --boot-filesystem=/boot/ \
++            --copy-default \
++            --mounts='test/grub2-support_files/g2.24-mounts'
++
++        testing="GRUB2 add kernel and initrd with rootfs on btrfs subvol and boot directory"
++        grub2Test grub2.25 add/g2-1.25 --add-kernel=/boot/new-kernel.img \
++            --title='title' \
++            --initrd=/boot/new-initrd \
++            --boot-filesystem= \
++            --copy-default \
++            --mounts='test/grub2-support_files/g2.25-mounts'
+     fi
+ fi
+ 
+diff --git a/test/grub2-support_files/g2.20-mounts b/test/grub2-support_files/g2.20-mounts
+new file mode 100644
+index 00000000000..00bdb48e4ab
+--- /dev/null
++++ b/test/grub2-support_files/g2.20-mounts
+@@ -0,0 +1,2 @@
++/dev/sda	/	btrfs	subvol=/root6,defaults	0 0
++/dev/sda	/boot	btrfs	subvol=/boot6,defaults	0 0
+diff --git a/test/grub2-support_files/g2.21-mounts b/test/grub2-support_files/g2.21-mounts
+new file mode 120000
+index 00000000000..42ef3fd4272
+--- /dev/null
++++ b/test/grub2-support_files/g2.21-mounts
+@@ -0,0 +1 @@
++g2.20-mounts
+\ No newline at end of file
+diff --git a/test/grub2-support_files/g2.22-mounts b/test/grub2-support_files/g2.22-mounts
+new file mode 100644
+index 00000000000..5b664e72519
+--- /dev/null
++++ b/test/grub2-support_files/g2.22-mounts
+@@ -0,0 +1 @@
++/dev/sda	/	btrfs	defaults,subvol=/root4,ro	0 0
+diff --git a/test/grub2-support_files/g2.23-mounts b/test/grub2-support_files/g2.23-mounts
+new file mode 120000
+index 00000000000..74f036fc4a3
+--- /dev/null
++++ b/test/grub2-support_files/g2.23-mounts
+@@ -0,0 +1 @@
++g2.22-mounts
+\ No newline at end of file
+diff --git a/test/grub2-support_files/g2.24-mounts b/test/grub2-support_files/g2.24-mounts
+new file mode 120000
+index 00000000000..42ef3fd4272
+--- /dev/null
++++ b/test/grub2-support_files/g2.24-mounts
+@@ -0,0 +1 @@
++g2.20-mounts
+\ No newline at end of file
+diff --git a/test/grub2-support_files/g2.25-mounts b/test/grub2-support_files/g2.25-mounts
+new file mode 120000
+index 00000000000..74f036fc4a3
+--- /dev/null
++++ b/test/grub2-support_files/g2.25-mounts
+@@ -0,0 +1 @@
++g2.22-mounts
+\ No newline at end of file
+diff --git a/test/grub2.20 b/test/grub2.20
+new file mode 100644
+index 00000000000..23b75fa8d3c
+--- /dev/null
++++ b/test/grub2.20
+@@ -0,0 +1,126 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-81378818f7a24478b496ebef90e1dd69' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-0-rescue-81378818f7a24478b496ebef90e1dd69 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-0-rescue-81378818f7a24478b496ebef90e1dd69.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/grub2.21 b/test/grub2.21
+new file mode 100644
+index 00000000000..579c2f6744a
+--- /dev/null
++++ b/test/grub2.21
+@@ -0,0 +1,140 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/new-kernel.img root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-81378818f7a24478b496ebef90e1dd69' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-0-rescue-81378818f7a24478b496ebef90e1dd69 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-0-rescue-81378818f7a24478b496ebef90e1dd69.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/grub2.22 b/test/grub2.22
+new file mode 100644
+index 00000000000..9466bc35153
+--- /dev/null
++++ b/test/grub2.22
+@@ -0,0 +1,128 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-20e7024f4e9c4b70b1042b91acd434c6' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-0-rescue-20e7024f4e9c4b70b1042b91acd434c6 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-0-rescue-20e7024f4e9c4b70b1042b91acd434c6.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/grub2.23 b/test/grub2.23
+new file mode 100644
+index 00000000000..5cb240fc1de
+--- /dev/null
++++ b/test/grub2.23
+@@ -0,0 +1,143 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/new-kernel.img root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-20e7024f4e9c4b70b1042b91acd434c6' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-0-rescue-20e7024f4e9c4b70b1042b91acd434c6 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-0-rescue-20e7024f4e9c4b70b1042b91acd434c6.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/grub2.24 b/test/grub2.24
+new file mode 100644
+index 00000000000..23b75fa8d3c
+--- /dev/null
++++ b/test/grub2.24
+@@ -0,0 +1,126 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-81378818f7a24478b496ebef90e1dd69' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-0-rescue-81378818f7a24478b496ebef90e1dd69 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-0-rescue-81378818f7a24478b496ebef90e1dd69.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/grub2.25 b/test/grub2.25
+new file mode 100644
+index 00000000000..9466bc35153
+--- /dev/null
++++ b/test/grub2.25
+@@ -0,0 +1,128 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-20e7024f4e9c4b70b1042b91acd434c6' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-0-rescue-20e7024f4e9c4b70b1042b91acd434c6 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-0-rescue-20e7024f4e9c4b70b1042b91acd434c6.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.20 b/test/results/add/g2-1.20
+new file mode 100644
+index 00000000000..579c2f6744a
+--- /dev/null
++++ b/test/results/add/g2-1.20
+@@ -0,0 +1,140 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/new-kernel.img root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-81378818f7a24478b496ebef90e1dd69' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-0-rescue-81378818f7a24478b496ebef90e1dd69 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-0-rescue-81378818f7a24478b496ebef90e1dd69.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.21 b/test/results/add/g2-1.21
+new file mode 100644
+index 00000000000..c0dded9724c
+--- /dev/null
++++ b/test/results/add/g2-1.21
+@@ -0,0 +1,141 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/new-kernel.img root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/new-initrd
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-81378818f7a24478b496ebef90e1dd69' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-0-rescue-81378818f7a24478b496ebef90e1dd69 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-0-rescue-81378818f7a24478b496ebef90e1dd69.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.22 b/test/results/add/g2-1.22
+new file mode 100644
+index 00000000000..5cb240fc1de
+--- /dev/null
++++ b/test/results/add/g2-1.22
+@@ -0,0 +1,143 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/new-kernel.img root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-20e7024f4e9c4b70b1042b91acd434c6' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-0-rescue-20e7024f4e9c4b70b1042b91acd434c6 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-0-rescue-20e7024f4e9c4b70b1042b91acd434c6.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.23 b/test/results/add/g2-1.23
+new file mode 100644
+index 00000000000..c3e87cf7897
+--- /dev/null
++++ b/test/results/add/g2-1.23
+@@ -0,0 +1,144 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/new-kernel.img root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/new-initrd
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-20e7024f4e9c4b70b1042b91acd434c6' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-0-rescue-20e7024f4e9c4b70b1042b91acd434c6 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-0-rescue-20e7024f4e9c4b70b1042b91acd434c6.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.24 b/test/results/add/g2-1.24
+new file mode 100644
+index 00000000000..c0dded9724c
+--- /dev/null
++++ b/test/results/add/g2-1.24
+@@ -0,0 +1,141 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/new-kernel.img root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/new-initrd
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-81378818f7a24478b496ebef90e1dd69' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	else
++	  search --no-floppy --fs-uuid --set=root 1bab15a4-93ce-4373-8d7d-b77f907fd0c6
++	fi
++	linux16 /boot6/vmlinuz-0-rescue-81378818f7a24478b496ebef90e1dd69 root=UUID=1bab15a4-93ce-4373-8d7d-b77f907fd0c6 ro rootflags=subvol=root6 rhgb quiet
++	initrd16 /boot6/initramfs-0-rescue-81378818f7a24478b496ebef90e1dd69.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/results/add/g2-1.25 b/test/results/add/g2-1.25
+new file mode 100644
+index 00000000000..c3e87cf7897
+--- /dev/null
++++ b/test/results/add/g2-1.25
+@@ -0,0 +1,144 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output console
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=15
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=15
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/10_linux ###
++menuentry 'title' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/new-kernel.img root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/new-initrd
++}
++menuentry 'Fedora, with Linux 3.15.0-0.rc7.git2.1.fc21.x86_64' --class gnu-linux --class gnu --class os {
++	load_video
++	set gfxpayload=keep
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-3.15.0-0.rc7.git2.1.fc21.x86_64 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-3.15.0-0.rc7.git2.1.fc21.x86_64.img
++}
++menuentry 'Fedora, with Linux 0-rescue-20e7024f4e9c4b70b1042b91acd434c6' --class gnu-linux --class gnu --class os {
++	load_video
++	insmod gzio
++	insmod part_msdos
++	insmod part_msdos
++	insmod btrfs
++	set root='hd0,msdos1'
++	if [ x$feature_platform_search_hint = xy ]; then
++	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  --hint='hd1,msdos3'  54c6abc2-b1e7-4987-aa73-c79927be69eb
++	else
++	  search --no-floppy --fs-uuid --set=root 54c6abc2-b1e7-4987-aa73-c79927be69eb
++	fi
++	linux16 /root4/boot/vmlinuz-0-rescue-20e7024f4e9c4b70b1042b91acd434c6 root=UUID=54c6abc2-b1e7-4987-aa73-c79927be69eb ro rootflags=subvol=root4 rhgb quiet
++	initrd16 /root4/boot/initramfs-0-rescue-20e7024f4e9c4b70b1042b91acd434c6.img
++}
++
++### END /etc/grub.d/10_linux ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+-- 
+2.17.1
+
diff --git a/SOURCES/0052-Use-system-LDFLAGS.patch b/SOURCES/0052-Use-system-LDFLAGS.patch
new file mode 100644
index 0000000..c13ca07
--- /dev/null
+++ b/SOURCES/0052-Use-system-LDFLAGS.patch
@@ -0,0 +1,24 @@
+From be8c1d611186d1fc35c50d417ba7b43ce25c6054 Mon Sep 17 00:00:00 2001
+From: Rafael dos Santos <rdossant@redhat.com>
+Date: Tue, 29 May 2018 15:15:24 +0200
+Subject: [PATCH 52/55] Use system LDFLAGS
+
+---
+ Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Makefile b/Makefile
+index cc7e823959f..65cd28295aa 100644
+--- a/Makefile
++++ b/Makefile
+@@ -25,6 +25,7 @@ OBJECTS = grubby.o log.o
+ CC = gcc
+ RPM_OPT_FLAGS ?= -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector
+ CFLAGS += $(RPM_OPT_FLAGS) -std=gnu99 -Wall -Werror -Wno-error=unused-function -Wno-unused-function -ggdb
++LDFLAGS := $(RPM_LD_FLAGS)
+ LDFLAGS := 
+ VERBOSE_TEST :=
+ ifneq ($(VERBOSE_TEST),)
+-- 
+2.17.1
+
diff --git a/SOURCES/0053-Honor-sbindir.patch b/SOURCES/0053-Honor-sbindir.patch
new file mode 100644
index 0000000..1cd9fbc
--- /dev/null
+++ b/SOURCES/0053-Honor-sbindir.patch
@@ -0,0 +1,36 @@
+From b4d5d14bef6861212f55148bbe6939a41700a54c Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 18 Jul 2018 13:41:02 -0400
+Subject: [PATCH 53/55] Honor sbindir
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 65cd28295aa..44fc12f0c1b 100644
+--- a/Makefile
++++ b/Makefile
+@@ -47,14 +47,14 @@ test: all
+ 	@./test.sh $(VERBOSE_TEST)
+ 
+ install: all
+-	mkdir -p $(DESTDIR)$(PREFIX)/sbin
++	mkdir -p $(DESTDIR)$(PREFIX)$(sbindir)
+ 	mkdir -p $(DESTDIR)/$(mandir)/man8
+-	install -m 755 new-kernel-pkg $(DESTDIR)$(PREFIX)/sbin
++	install -m 755 new-kernel-pkg $(DESTDIR)$(PREFIX)$(sbindir)
+ 	install -m 644 new-kernel-pkg.8 $(DESTDIR)/$(mandir)/man8
+-	install -m 755 installkernel $(DESTDIR)$(PREFIX)/sbin
++	install -m 755 installkernel $(DESTDIR)$(PREFIX)$(sbindir)
+ 	install -m 644 installkernel.8 $(DESTDIR)/$(mandir)/man8
+ 	if [ -f grubby ]; then \
+-		install -m 755 grubby $(DESTDIR)$(PREFIX)/sbin ; \
++		install -m 755 grubby $(DESTDIR)$(PREFIX)$(sbindir) ; \
+ 		install -m 644 grubby.8 $(DESTDIR)/$(mandir)/man8 ; \
+ 	fi
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0054-Make-installkernel-to-use-kernel-install-scripts-on-.patch b/SOURCES/0054-Make-installkernel-to-use-kernel-install-scripts-on-.patch
new file mode 100644
index 0000000..4a4d841
--- /dev/null
+++ b/SOURCES/0054-Make-installkernel-to-use-kernel-install-scripts-on-.patch
@@ -0,0 +1,48 @@
+From f8482113065878c0ace605fbca296fc7601c47cc Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 31 Jul 2018 17:43:53 +0200
+Subject: [PATCH 54/55] Make installkernel to use kernel-install scripts on BLS
+ configuration
+
+The kernel make install target executes the arch/$ARCH/boot/install.sh
+that in turns executes the distro specific installkernel script. This
+script always uses new-kernel-pkg to install the kernel images.
+
+But on a BootLoaderSpec setup, the kernel-install scripts must be used
+instead. Check if the system uses a BLS setup, and call kernel-install
+add in that case instead of new-kernel-pkg.
+
+Reported-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ installkernel | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/installkernel b/installkernel
+index b887929c179..68dcfac16d2 100755
+--- a/installkernel
++++ b/installkernel
+@@ -20,6 +20,8 @@
+ # Author(s): tyson@rwii.com
+ #
+ 
++[[ -f /etc/default/grub ]] && . /etc/default/grub
++
+ usage() {
+     echo "Usage: `basename $0` <kernel_version> <bootimage> <mapfile>" >&2
+     exit 1
+@@ -77,6 +79,11 @@ cp $MAPFILE $INSTALL_PATH/System.map-$KERNEL_VERSION
+ ln -fs ${RELATIVE_PATH}$INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION $LINK_PATH/$KERNEL_NAME
+ ln -fs ${RELATIVE_PATH}$INSTALL_PATH/System.map-$KERNEL_VERSION $LINK_PATH/System.map
+ 
++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ] || [ ! -f /sbin/new-kernel-pkg ]; then
++	kernel-install add $KERNEL_VERSION $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION
++	exit $?
++fi
++
+ if [ -n "$cfgLoader" ] && [ -x /sbin/new-kernel-pkg ]; then
+ 	if [ -n "$(which dracut 2>/dev/null)" ]; then
+ 		new-kernel-pkg --mkinitrd --dracut --host-only --depmod --install --kernel-name $KERNEL_NAME $KERNEL_VERSION
+-- 
+2.17.1
+
diff --git a/SOURCES/0055-Add-usr-libexec-rpm-sort.patch b/SOURCES/0055-Add-usr-libexec-rpm-sort.patch
new file mode 100644
index 0000000..fffc59d
--- /dev/null
+++ b/SOURCES/0055-Add-usr-libexec-rpm-sort.patch
@@ -0,0 +1,419 @@
+From 4e0e028b21070f956b144bd530230d01b9015d73 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 12 Oct 2018 16:39:37 -0400
+Subject: [PATCH 55/55] Add /usr/libexec/rpm-sort
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ rpm-sort.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Makefile   |   9 +-
+ .gitignore |   1 +
+ 3 files changed, 363 insertions(+), 2 deletions(-)
+ create mode 100644 rpm-sort.c
+
+diff --git a/rpm-sort.c b/rpm-sort.c
+new file mode 100644
+index 00000000000..f19635645ba
+--- /dev/null
++++ b/rpm-sort.c
+@@ -0,0 +1,355 @@
++#define _GNU_SOURCE
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <assert.h>
++#include <argp.h>
++#include <rpm/rpmlib.h>
++#include <err.h>
++
++typedef enum {
++        RPMNVRCMP,
++        VERSNVRCMP,
++        RPMVERCMP,
++        STRVERSCMP,
++} comparitors;
++
++static comparitors comparitor = RPMNVRCMP;
++
++static inline void *xmalloc(size_t sz)
++{
++        void *ret = malloc(sz);
++
++        assert(sz == 0 || ret != NULL);
++        return ret;
++}
++
++static inline void *xrealloc(void *p, size_t sz)
++{
++        void *ret = realloc(p, sz);
++
++        assert(sz == 0 || ret != NULL);
++        return ret;
++}
++
++static inline char *xstrdup(const char * const s)
++{
++        void *ret = strdup(s);
++
++        assert(s == NULL || ret != NULL);
++        return ret;
++}
++
++static size_t
++read_file (const char *input, char **ret)
++{
++  FILE *in;
++  size_t s;
++  size_t sz = 2048;
++  size_t offset = 0;
++  char *text;
++
++  if (!strcmp(input, "-"))
++    in = stdin;
++  else
++    in = fopen(input, "r");
++
++  text = xmalloc (sz);
++
++  if (!in)
++    err(1, "cannot open `%s'", input);
++
++  while ((s = fread (text + offset, 1, sz - offset, in)) != 0)
++    {
++      offset += s;
++      if (sz - offset == 0)
++	{
++	  sz += 2048;
++	  text = xrealloc (text, sz);
++	}
++    }
++
++  text[offset] = '\0';
++  *ret = text;
++
++  if (in != stdin)
++    fclose(in);
++
++  return offset + 1;
++}
++
++/* returns name/version/release */
++/* NULL string pointer returned if nothing found */
++static void
++split_package_string (char *package_string, char **name,
++                     char **version, char **release)
++{
++  char *package_version, *package_release;
++
++  /* Release */
++  package_release = strrchr (package_string, '-');
++
++  if (package_release != NULL)
++      *package_release++ = '\0';
++
++  *release = package_release;
++
++  /* Version */
++  package_version = strrchr(package_string, '-');
++
++  if (package_version != NULL)
++      *package_version++ = '\0';
++
++  *version = package_version;
++  /* Name */
++  *name = package_string;
++
++  /* Bubble up non-null values from release to name */
++  if (*name == NULL)
++    {
++      *name = (*version == NULL ? *release : *version);
++      *version = *release;
++      *release = NULL;
++    }
++  if (*version == NULL)
++    {
++      *version = *release;
++      *release = NULL;
++    }
++}
++
++static int
++cmprpmversp(const void *p1, const void *p2)
++{
++        return rpmvercmp(*(char * const *)p1, *(char * const *)p2);
++}
++
++static int
++cmpstrversp(const void *p1, const void *p2)
++{
++        return strverscmp(*(char * const *)p1, *(char * const *)p2);
++}
++
++/*
++ * package name-version-release comparator for qsort
++ * expects p, q which are pointers to character strings (char *)
++ * which will not be altered in this function
++ */
++static int
++package_version_compare (const void *p, const void *q)
++{
++  char *local_p, *local_q;
++  char *lhs_name, *lhs_version, *lhs_release;
++  char *rhs_name, *rhs_version, *rhs_release;
++  int vercmpflag = 0;
++  int (*cmp)(const char *s1, const char *s2);
++
++  switch(comparitor)
++    {
++    default: /* just to shut up -Werror=maybe-uninitialized */
++    case RPMNVRCMP:
++      cmp = rpmvercmp;
++      break;
++    case VERSNVRCMP:
++      cmp = strverscmp;
++      break;
++    case RPMVERCMP:
++      return cmprpmversp(p, q);
++      break;
++    case STRVERSCMP:
++      return cmpstrversp(p, q);
++      break;
++    }
++
++  local_p = alloca (strlen (*(char * const *)p) + 1);
++  local_q = alloca (strlen (*(char * const *)q) + 1);
++
++  /* make sure these allocated */
++  assert (local_p);
++  assert (local_q);
++
++  strcpy (local_p, *(char * const *)p);
++  strcpy (local_q, *(char * const *)q);
++
++  split_package_string (local_p, &lhs_name, &lhs_version, &lhs_release);
++  split_package_string (local_q, &rhs_name, &rhs_version, &rhs_release);
++
++  /* Check Name and return if unequal */
++  vercmpflag = cmp ((lhs_name == NULL ? "" : lhs_name),
++                    (rhs_name == NULL ? "" : rhs_name));
++  if (vercmpflag != 0)
++    return vercmpflag;
++
++  /* Check version and return if unequal */
++  vercmpflag = cmp ((lhs_version == NULL ? "" : lhs_version),
++                    (rhs_version == NULL ? "" : rhs_version));
++  if (vercmpflag != 0)
++    return vercmpflag;
++
++  /* Check release and return the version compare value */
++  vercmpflag = cmp ((lhs_release == NULL ? "" : lhs_release),
++                    (rhs_release == NULL ? "" : rhs_release));
++
++  return vercmpflag;
++}
++
++static void
++add_input (const char *filename, char ***package_names, size_t *n_package_names)
++{
++  char *orig_input_buffer = NULL;
++  char *input_buffer;
++  char *position_of_newline;
++  char **names = *package_names;
++  char **new_names = NULL;
++  size_t n_names = *n_package_names;
++
++  if (!*package_names)
++    new_names = names = xmalloc (sizeof (char *) * 2);
++
++  if (read_file (filename, &orig_input_buffer) < 2)
++    {
++      if (new_names)
++	free (new_names);
++      if (orig_input_buffer)
++	free (orig_input_buffer);
++      return;
++    }
++
++  input_buffer = orig_input_buffer;
++  while (input_buffer && *input_buffer &&
++	 (position_of_newline = strchrnul (input_buffer, '\n')))
++    {
++      size_t sz = position_of_newline - input_buffer;
++      char *new;
++
++      if (sz == 0)
++	{
++	  input_buffer = position_of_newline + 1;
++	  continue;
++	}
++
++      new = xmalloc (sz+1);
++      strncpy (new, input_buffer, sz);
++      new[sz] = '\0';
++
++      names = xrealloc (names, sizeof (char *) * (n_names + 1));
++      names[n_names] = new;
++      n_names++;
++
++      /* move buffer ahead to next line */
++      input_buffer = position_of_newline + 1;
++      if (*position_of_newline == '\0')
++	input_buffer = NULL;
++    }
++
++  free (orig_input_buffer);
++
++  *package_names = names;
++  *n_package_names = n_names;
++}
++
++static char *
++help_filter (int key, const char *text, void *input __attribute__ ((unused)))
++{
++  return (char *)text;
++}
++
++static struct argp_option options[] = {
++  { "comparitor", 'c', "COMPARITOR", 0, "[rpm-nvr-cmp|vers-nvr-cmp|rpmvercmp|strverscmp]", 0},
++  { 0, }
++};
++
++struct arguments
++{
++  size_t ninputs;
++  size_t input_max;
++  char **inputs;
++};
++
++static error_t
++argp_parser (int key, char *arg, struct argp_state *state)
++{
++  struct arguments *arguments = state->input;
++  switch (key)
++    {
++    case 'c':
++      if (!strcmp(arg, "rpm-nvr-cmp") || !strcmp(arg, "rpmnvrcmp"))
++        comparitor = RPMNVRCMP;
++      else if (!strcmp(arg, "vers-nvr-cmp") || !strcmp(arg, "versnvrcmp"))
++        comparitor = VERSNVRCMP;
++      else if (!strcmp(arg, "rpmvercmp"))
++        comparitor = RPMVERCMP;
++      else if (!strcmp(arg, "strverscmp"))
++        comparitor = STRVERSCMP;
++      else
++        err(1, "Invalid comparitor \"%s\"", arg);
++      break;
++    case ARGP_KEY_ARG:
++      assert (arguments->ninputs < arguments->input_max);
++      arguments->inputs[arguments->ninputs++] = xstrdup (arg);
++      break;
++    default:
++      return ARGP_ERR_UNKNOWN;
++    }
++  return 0;
++}
++
++static struct argp argp = {
++  options, argp_parser, "[INPUT_FILES]",
++  "Sort a list of strings in RPM version sort order.",
++  NULL, help_filter, NULL
++};
++
++int
++main (int argc, char *argv[])
++{
++  struct arguments arguments;
++  char **package_names = NULL;
++  size_t n_package_names = 0;
++  int i;
++
++  memset (&arguments, 0, sizeof (struct arguments));
++  arguments.input_max = argc+1;
++  arguments.inputs = xmalloc ((arguments.input_max + 1)
++			      * sizeof (arguments.inputs[0]));
++  memset (arguments.inputs, 0, (arguments.input_max + 1)
++	  * sizeof (arguments.inputs[0]));
++
++  /* Parse our arguments */
++  if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
++    errx(1, "%s", "Error in parsing command line arguments\n");
++
++  /* If there's no inputs in argv, add one for stdin */
++  if (!arguments.ninputs)
++    {
++      arguments.ninputs = 1;
++      arguments.inputs[0] = xmalloc (2);
++      strcpy(arguments.inputs[0], "-");
++    }
++
++  for (i = 0; i < arguments.ninputs; i++)
++    add_input(arguments.inputs[i], &package_names, &n_package_names);
++
++  if (package_names == NULL || n_package_names < 1)
++    errx(1, "Invalid input");
++
++  qsort (package_names, n_package_names, sizeof (char *),
++	 package_version_compare);
++
++  /* send sorted list to stdout */
++  for (i = 0; i < n_package_names; i++)
++    {
++      fprintf (stdout, "%s\n", package_names[i]);
++      free (package_names[i]);
++    }
++
++  free (package_names);
++  for (i = 0; i < arguments.ninputs; i++)
++    free (arguments.inputs[i]);
++
++  free (arguments.inputs);
++
++  return 0;
++}
+diff --git a/Makefile b/Makefile
+index 44fc12f0c1b..8eeec80da21 100644
+--- a/Makefile
++++ b/Makefile
+@@ -34,7 +34,7 @@ endif
+ 
+ grubby_LIBS = -lblkid -lpopt
+ 
+-all: grubby
++all: grubby rpm-sort
+ 
+ debug : clean
+ 	$(MAKE) CFLAGS="${CFLAGS} -DDEBUG=1" all
+@@ -57,12 +57,17 @@ install: all
+ 		install -m 755 grubby $(DESTDIR)$(PREFIX)$(sbindir) ; \
+ 		install -m 644 grubby.8 $(DESTDIR)/$(mandir)/man8 ; \
+ 	fi
++	install -m 755 -d $(DESTDIR)$(PREFIX)$(libexecdir)/grubby/
++	install -m 755 rpm-sort $(DESTDIR)$(PREFIX)$(libexecdir)/grubby/rpm-sort
+ 
+ grubby:: $(OBJECTS)
+ 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(grubby_LIBS)
+ 
++rpm-sort::rpm-sort.o
++	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lrpm
++
+ clean:
+-	rm -f *.o grubby *~
++	rm -f *.o grubby rpm-sort *~
+ 
+ GITTAG = $(VERSION)-1
+ 
+diff --git a/.gitignore b/.gitignore
+index 1c00ff7c5ed..bcaf1494f61 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -1,4 +1,5 @@
+ grubby
++rpm-sort
+ version.h
+ *.o
+ core.*
+-- 
+2.17.1
+
diff --git a/SOURCES/0056-Improve-man-page-for-info-option.patch b/SOURCES/0056-Improve-man-page-for-info-option.patch
new file mode 100644
index 0000000..e5d3c0a
--- /dev/null
+++ b/SOURCES/0056-Improve-man-page-for-info-option.patch
@@ -0,0 +1,30 @@
+From e15806969cbae83a94068d99e4f1d295dab95eac Mon Sep 17 00:00:00 2001
+From: Jan Stodola <jstodola@redhat.com>
+Date: Tue, 20 Nov 2018 15:02:19 +0100
+Subject: [PATCH] Improve man page for --info option
+
+1) commit 941d4a0b removed description of --info DEFAULT
+2) Add description of --info ALL
+---
+ grubby.8 | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/grubby.8 b/grubby.8
+index 1e8f140c4df..8b98433960c 100644
+--- a/grubby.8
++++ b/grubby.8
+@@ -185,7 +185,10 @@ Display the title of the current default boot entry and exit.
+ 
+ .TP
+ \fB-\-info\fR=\fIkernel-path\fR
+-Display information on all boot entries which match \fIkernel-path\fR. I
++Display information on all boot entries which match \fIkernel-path\fR. If
++\fIkernel-path\fR is \fBDEFAULT\fR, then information on the default kernel
++is displayed. If \fIkernel-path\fR is \fBALL\fR, then information on all boot
++entries are displayed.
+ 
+ .TP
+ \fB-\-bootloader-probe\fR
+-- 
+2.19.1
+
diff --git a/SOURCES/grubby-bls b/SOURCES/grubby-bls
new file mode 100755
index 0000000..8f4b73c
--- /dev/null
+++ b/SOURCES/grubby-bls
@@ -0,0 +1,750 @@
+#!/bin/bash
+#
+# grubby wrapper to manage BootLoaderSpec files
+#
+#
+# Copyright 2018 Red Hat, Inc.  All rights reserved.
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+readonly SCRIPTNAME="${0##*/}"
+
+CMDLINE_LINUX_DEBUG=" systemd.log_level=debug systemd.log_target=kmsg"
+LINUX_DEBUG_VERSION_POSTFIX="_with_debugging"
+LINUX_DEBUG_TITLE_POSTFIX=" with debugging"
+
+declare -a bls_file
+declare -a bls_title
+declare -a bls_version
+declare -a bls_linux
+declare -a bls_initrd
+declare -a bls_options
+declare -a bls_id
+
+[[ -f /etc/sysconfig/kernel ]] && . /etc/sysconfig/kernel
+[[ -f /etc/os-release ]] && . /etc/os-release
+read MACHINE_ID < /etc/machine-id
+arch=$(uname -m)
+
+if [[ $arch = 's390' || $arch = 's390x' ]]; then
+    bootloader="zipl"
+else
+    bootloader="grub2"
+fi
+
+print_error() {
+    echo "$1" >&2
+    exit 1
+}
+
+print_info() {
+    echo "$1" >&2
+}
+
+if [[ ${#} = 0 ]]; then
+    print_error "no action specified"
+fi
+
+get_bls_value() {
+    local bls="$1" && shift
+    local key="$1" && shift
+
+    echo "$(grep "^${key}[ \t]" "${bls}" | sed -e "s!^${key}[ \t]*!!")"
+}
+
+set_bls_value() {
+    local bls="$1" && shift
+    local key="$1" && shift
+    local value="$1" && shift
+
+    value=$(echo $value | sed -e 's/\//\\\//g')
+    sed -i -e "s/^${key}.*/${key} ${value}/" "${bls}"
+}
+
+append_bls_value() {
+    local bls="$1" && shift
+    local key="$1" && shift
+    local value="$1" && shift
+
+    old_value="$(get_bls_value "${bls}" ${key})"
+    set_bls_value "${bls}" "${key}" "${old_value}${value}"
+}
+
+get_bls_values() {
+    count=0
+    local -a files
+    local IFS=$'\n'
+    files=($(for bls in ${blsdir}/*.conf ; do
+        if ! [[ -e "${bls}" ]] ; then
+            continue
+        fi
+        bls="${bls%.conf}"
+        bls="${bls##*/}"
+        echo "${bls}"
+    done | /usr/libexec/grubby/rpm-sort -c rpmnvrcmp | tac)) || :
+
+    for bls in "${files[@]}" ; do
+        blspath="${blsdir}/${bls}.conf"
+        bls_file[$count]="${blspath}"
+        bls_title[$count]="$(get_bls_value ${blspath} title)"
+        bls_version[$count]="$(get_bls_value ${blspath} version)"
+        bls_linux[$count]="$(get_bls_value ${blspath} linux)"
+        bls_initrd[$count]="$(get_bls_value ${blspath} initrd)"
+        bls_options[$count]="$(get_bls_value ${blspath} options)"
+        bls_id[$count]="${bls}"
+
+        count=$((count+1))
+    done
+}
+
+get_default_index() {
+    local default=""
+    local index="-1"
+    local title=""
+    local version=""
+    if [[ $bootloader = "grub2" ]]; then
+	default="$(grep '^saved_entry=' ${env} | sed -e 's/^saved_entry=//')"
+    else
+	default="$(grep '^default=' ${zipl_config} | sed -e 's/^default=//')"
+    fi
+
+    if [[ -z $default ]]; then
+	index=0
+    elif [[ $default =~ ^[0-9]+$ ]]; then
+	index="$default"
+    fi
+
+    for i in ${!bls_file[@]}; do
+        if [[ $i -eq $index ]]; then
+            echo $i
+            return
+        fi
+
+        if [[ $default = ${bls_id[$i]} || $default = ${bls_title[$i]} ]]; then
+            echo $i
+            return
+        fi
+    done
+}
+
+display_default_value() {
+    local prefix=$(get_prefix)
+
+    case "$display_default" in
+        kernel)
+            echo "${prefix}${bls_linux[$default_index]}"
+            exit 0
+            ;;
+        index)
+            echo "$default_index"
+            exit 0
+            ;;
+        title)
+            echo "${bls_title[$default_index]}"
+            exit 0
+            ;;
+    esac
+}
+
+param_to_indexes() {
+    local param="$1"
+    local indexes=""
+
+    if [[ $param = "ALL" ]]; then
+        for i in ${!bls_file[@]}; do
+            indexes="$indexes $i"
+        done
+        echo -n $indexes
+        return
+    fi
+
+    if [[ $param = "DEFAULT" ]]; then
+        echo -n $default_index
+        return
+    fi
+
+    for i in ${!bls_file[@]}; do
+        if [[ $param = "${bls_linux[$i]}" || "/${param##*/}" = "${bls_linux[$i]}" ]]; then
+            indexes="$indexes $i"
+        fi
+
+        if [[ $param = "TITLE=${bls_title[$i]}" ]]; then
+            indexes="$indexes $i"
+        fi
+
+	if [[ $param = $i ]]; then
+	    indexes="$indexes $i"
+	fi
+    done
+
+    if [[ -n $indexes ]]; then
+        echo -n $indexes
+        return
+    fi
+
+    echo -n "-1"
+}
+
+get_prefix() {
+    if [[ $bootloader = grub2 ]] && grep -q /boot /proc/mounts; then
+	echo "/boot"
+    else
+	echo ""
+    fi
+}
+
+expand_var() {
+    local var=$1
+
+    if [[ $bootloader == "grub2" ]]; then
+        local value="$(grub2-editenv "${env}" list | grep ${var##$} | sed -e "s/${var##$}=//")"
+        value="$(echo ${value} | sed -e 's/\//\\\//g')"
+        if [[ -n $value ]]; then
+            var="$value"
+        fi
+    fi
+
+    echo $var
+}
+
+get_bls_args() {
+    local args=${bls_options[$i]}
+    local opts=(${args})
+
+    for opt in ${opts[*]}; do
+        if [[ $opt =~ ^\$ ]]; then
+            value="$(expand_var $opt)"
+            args="$(echo ${args} | sed -e "s/${opt}/${value}/")"
+        fi
+    done
+
+    echo ${args}
+}
+
+display_info_values() {
+    local indexes=($(param_to_indexes "$1"))
+    local prefix=$(get_prefix)
+
+    if [[ $indexes = "-1" ]]; then
+        print_error "The param $1 is incorrect"
+    fi
+
+    for i in ${indexes[*]}; do
+        local root=""
+        local value=""
+        local args="$(get_bls_args "$i")"
+
+        local opts=(${args})
+
+        for opt in ${opts[*]}; do
+            if echo $opt | grep -q "^root="; then
+                root="$(echo $opt | sed -e 's/root=//')"
+                value="$(echo ${opt} | sed -e 's/\//\\\//g')"
+                args="$(echo ${args} | sed -e "s/${value}[ \t]*//")"
+                break
+            fi
+        done
+
+        echo "index=$i"
+        echo "kernel=\"${prefix}${bls_linux[$i]}\""
+        echo "args=\"${args}\""
+
+        if [[ -n $root ]]; then
+            echo "root=\"${root}\""
+        fi
+
+        echo "initrd=\"${prefix}${bls_initrd[$i]}\""
+        echo "title=\"${bls_title[$i]}\""
+        echo "id=\"${bls_id[$i]}\""
+    done
+    exit 0
+}
+
+mkbls() {
+    local kernel=$1 && shift
+    local kernelver=$1 && shift
+    local datetime=$1 && shift
+
+    local debugname=""
+    local flavor=""
+    local prefix=""
+
+    if [[ $(get_prefix) = "" ]]; then
+	prefix="/boot"
+    fi
+
+    if [[ $kernelver == *\+* ]] ; then
+        local flavor=-"${kernelver##*+}"
+        if [[ $flavor == "-debug" ]]; then
+            local debugname="with debugging"
+	    local debugid="-debug"
+        fi
+    fi
+
+    cat <<EOF
+title ${NAME} (${kernelver}) ${VERSION}${debugname}
+version ${kernelver}${debugid}
+linux ${kernel}
+initrd ${prefix}/initramfs-${kernelver}.img
+options \$kernelopts
+id ${ID}-${datetime}-${kernelver}${debugid}
+grub_users \$grub_users
+grub_arg --unrestricted
+grub_class kernel${flavor}
+EOF
+}
+
+remove_bls_fragment() {
+    local indexes=($(param_to_indexes "$1"))
+
+    if [[ $indexes = "-1" ]]; then
+	print_error "The param $1 is incorrect"
+    fi
+
+    for i in "${indexes[@]}"; do
+        rm -f "${bls_file[$i]}"
+    done
+
+    get_bls_values
+
+    update_grubcfg
+}
+
+get_custom_bls_filename() {
+    local kernelver=$1
+    local bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
+    count=0
+    local -a files
+    local IFS=$'\n'
+
+    prefix="${bls_target%%.conf}"
+    prefix="${bls_target%%${arch}}"
+    prefix="${prefix%.*}"
+
+    last=($(for bls in ${prefix}.*~custom*.conf ; do
+        if ! [[ -e "${bls}" ]] ; then
+            continue
+        fi
+        bls="${bls##${prefix}.}"
+        bls="${bls%%~custom*}"
+        echo "${bls}"
+    done | tail -n1)) || :
+
+    if [[ -z $last ]]; then
+        last="0"
+    else
+        last=$((last+1))
+    fi
+
+    echo "${bls_target}" | sed -e "s!${prefix}!${prefix}.${last}~custom!"
+}
+
+add_bls_fragment() {
+    local kernel="$1" && shift
+    local title="$1" && shift
+    local options="$1" && shift
+    local initrd="$1" && shift
+    local extra_initrd="$1" && shift
+
+    if [[ $kernel = *"vmlinuz-"* ]]; then
+	kernelver="${kernel##*/vmlinuz-}"
+	prefix="vmlinuz-"
+    else
+	kernelver="${kernel##*/}"
+    fi
+
+    if [[ ! -f "/boot/${prefix}${kernelver}" ]] &&
+       [[ $bad_image != "true" ]]; then
+        print_error "The ${kernelver} kernel isn't installed in the machine"
+    fi
+
+    if [[ -z $title ]]; then
+	print_error "The kernel title must be specified"
+    fi
+
+    if [[ ! -d $blsdir ]]; then
+        install -m 700 -d "${blsdir}"
+    fi
+
+    bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
+
+    if [[ -e ${bls_target} ]]; then
+        bls_target="$(get_custom_bls_filename "${kernelver}")"
+        print_info "An entry for kernel ${kernelver} already exists, adding ${bls_target}"
+    fi
+
+    kernel_dir="/lib/modules/${kernelver}"
+    if [[ -d $kernel_dir ]]; then
+        datetime="$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")"
+    else
+        datetime=0
+    fi
+    mkbls "${kernel}" "${kernelver}" "${datetime}" > "${bls_target}"
+
+    if [[ -n $title ]]; then
+        set_bls_value "${bls_target}" "title" "${title}"
+    fi
+
+    if [[ -n $options ]]; then
+        set_bls_value "${bls_target}" "options" "${options}"
+    fi
+
+    if [[ -n $initrd ]]; then
+        set_bls_value "${bls_target}" "initrd" "${initrd}"
+    fi
+
+    if [[ -n $extra_initrd ]]; then
+        append_bls_value "${bls_target}" "initrd" "${extra_initrd}"
+    fi
+
+    if [[ $MAKEDEBUG = "yes" ]]; then
+        bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")"
+        cp -aT  "${bls_target}" "${bls_debug}"
+        append_bls_value "${bls_debug}" "title" "${LINUX_DEBUG_TITLE_POSTFIX}"
+        append_bls_value "${bls_debug}" "version" "${LINUX_DEBUG_VERSION_POSTFIX}"
+        append_bls_value "${bls_debug}" "options" "${CMDLINE_LINUX_DEBUG}"
+        blsid="$(get_bls_value ${bls_debug} "id" | sed -e "s/${kernelver}/${kernelver}~debug/")"
+        set_bls_value "${bls_debug}" "id" "${blsid}"
+    fi
+
+    get_bls_values
+
+    if [[ $make_default = "true" ]]; then
+        set_default_bls "TITLE=${title}"
+    fi
+
+    update_grubcfg
+
+    exit 0
+}
+
+update_args() {
+    local args=$1 && shift
+    local remove_args=($1) && shift
+    local add_args=($1) && shift
+
+    for arg in ${remove_args[*]}; do
+        if [[ $arg = *"="* ]]; then
+            arg=$(echo $arg | sed -e 's/\//\\\//g')
+            args="$(echo $args | sed -E "s/(^|[[:space:]])$arg([[:space:]]|$)/ /")"
+        else
+            args="$(echo $args | sed -E "s/(^|[[:space:]])$arg(([[:space:]]|$)|([=][^ ]*([$]*)))/ /g")"
+        fi
+    done
+
+    for arg in ${add_args[*]}; do
+        arg=${arg%=*}
+        args="$(echo $args | sed -E "s/(^|[[:space:]])$arg(([[:space:]]|$)|([=][^ ]*([$]*)))/ /g")"
+    done
+
+    for arg in ${add_args[*]}; do
+        args="$args $arg"
+    done
+
+    echo ${args}
+}
+
+update_bls_fragment() {
+    local indexes=($(param_to_indexes "$1")) && shift
+    local remove_args=$1 && shift
+    local add_args=$1 && shift
+    local initrd=$1 && shift
+
+    if [[ $indexes = "-1" ]]; then
+        print_error "The param $1 is incorrect"
+    fi
+
+    for i in ${indexes[*]}; do
+	if [[ -n $remove_args || -n $add_args ]]; then
+            local old_args="$(get_bls_args "$i")"
+            local new_args="$(update_args "${old_args}" "${remove_args}" "${add_args}")"
+            set_bls_value "${bls_file[$i]}" "options" "${new_args}"
+	fi
+
+	if [[ -n $initrd ]]; then
+	    set_bls_value "${bls_file[$i]}" "initrd" "${initrd}"
+	fi
+    done
+
+    update_grubcfg
+}
+
+set_default_bls() {
+    local index=($(param_to_indexes "$1"))
+
+    if [[ $index = "-1" ]]; then
+        print_error "The param $1 is incorrect"
+    fi
+
+    if [[ $bootloader = grub2 ]]; then
+        grub2-editenv "${env}" set saved_entry="${bls_id[$index]}"
+    else
+        local default="${bls_title[$index]}"
+        local current="$(grep '^default=' ${zipl_config} | sed -e 's/^default=//')"
+        if [[ -n $current ]]; then
+            sed -i -e "s,^default=.*,default=${default}," "${zipl_config}"
+        else
+            echo "default=${default}" >> "${zipl_config}"
+        fi
+    fi
+
+    print_info "The default is ${bls_file[$index]} with index $index and kernel $(get_prefix)${bls_linux[$index]}"
+}
+
+remove_var_prefix() {
+    if [[ -n $remove_kernel && $remove_kernel =~ ^/ ]]; then
+       remove_kernel="/${remove_kernel##*/}"
+    fi
+
+    if [[ -n $initrd ]]; then
+	initrd="/${initrd##*/}"
+    fi
+
+    if [[ -n $extra_initrd ]]; then
+	extra_initrd=" /${extra_initrd##*/}"
+    fi
+
+    if [[ -n $kernel ]]; then
+	kernel="/${kernel##*/}"
+    fi
+
+    if [[ -n $update_kernel && $update_kernel =~ ^/ ]]; then
+	update_kernel="/${update_kernel##*/}"
+    fi
+}
+
+update_grubcfg()
+{
+    if [[ $arch = 'ppc64' || $arch = 'ppc64le' ]]; then
+	grub2-mkconfig -o /boot/grub2/grub.cfg >& /dev/null
+    fi
+}
+
+print_usage()
+{
+    cat <<EOF
+Usage: grubby [OPTION...]
+      --add-kernel=kernel-path            add an entry for the specified kernel
+      --args=args                         default arguments for the new kernel or new arguments for kernel being updated)
+      --bad-image-okay                    don't sanity check images in boot entries (for testing only)
+  -c, --config-file=path                  path to grub config file to update ("-" for stdin)
+      --copy-default                      use the default boot entry as a template for the new entry being added; if the default is not a linux image, or if the kernel referenced by the default image does not exist, the
+                                          first linux entry whose kernel does exist is used as the template
+      --default-kernel                    display the path of the default kernel
+      --default-index                     display the index of the default kernel
+      --default-title                     display the title of the default kernel
+      --env=path                          path for environment data
+      --grub2                             configure grub2 bootloader
+      --info=kernel-path                  display boot information for specified kernel
+      --initrd=initrd-path                initrd image for the new kernel
+  -i, --extra-initrd=initrd-path          auxiliary initrd image for things other than the new kernel
+      --make-default                      make the newly added entry the default boot entry
+  -o, --output-file=path                  path to output updated config file ("-" for stdout)
+      --remove-args=STRING                remove kernel arguments
+      --remove-kernel=kernel-path         remove all entries for the specified kernel
+      --set-default=kernel-path           make the first entry referencing the specified kernel the default
+      --set-default-index=entry-index     make the given entry index the default entry
+      --title=entry-title                 title to use for the new kernel entry
+      --update-kernel=kernel-path         updated information for the specified kernel
+      --zipl                              configure zipl bootloader
+  -b, --bls-directory                     path to directory containing the BootLoaderSpec fragment files
+
+Help options:
+  -?, --help                              Show this help message
+
+EOF
+}
+
+OPTS="$(getopt -o c:i:o:b:? --long help,add-kernel:,args:,bad-image-okay,\
+config-file:,copy-default,default-kernel,default-index,default-title,env:,\
+grub2,info:,initrd:,extra-initrd:,make-default,output-file:,remove-args:,\
+remove-kernel:,set-default:,set-default-index:,title:,update-kernel:,zipl,\
+bls-directory:,add-kernel:,add-multiboot:,mbargs:,mounts:,boot-filesystem:,\
+bootloader-probe,debug,devtree,devtreedir:,elilo,efi,extlinux,grub,lilo,\
+output-file:,remove-mbargs:,remove-multiboot:,silo,yaboot -n ${SCRIPTNAME} -- "$@")"
+
+[[ $? = 0 ]] || exit 1
+
+eval set -- "$OPTS"
+
+while [ ${#} -gt 0 ]; do
+    case "$1" in
+        --help|-h)
+            print_usage
+            exit 0
+            ;;
+        --add-kernel)
+            kernel="${2}"
+            shift
+            ;;
+        --args)
+            args="${2}"
+            shift
+            ;;
+        --bad-image-okay)
+            bad_image=true
+            ;;
+        --config-file|-c)
+            zipl_config="${2}"
+            shift
+            ;;
+        --copy-default)
+            copy_default=true
+            ;;
+        --default-kernel)
+            display_default="kernel"
+            ;;
+        --default-index)
+            display_default="index"
+            ;;
+        --default-title)
+            display_default="title"
+            ;;
+        --env)
+            env="${2}"
+            shift
+            ;;
+        --grub2)
+            bootloader="grub2"
+            ;;
+        --info)
+            display_info="${2}"
+            shift
+            ;;
+        --initrd)
+            initrd="${2}"
+            shift
+            ;;
+        --extra-initrd|-i)
+            extra_initrd=" /${2}"
+            shift
+            ;;
+        --make-default)
+            make_default=true
+            ;;
+        --output-file|-o)
+            output_file="${2}"
+            shift
+            ;;
+        --remove-args)
+            remove_args="${2}"
+            shift
+            ;;
+        --remove-kernel)
+            remove_kernel="${2}"
+            shift
+            ;;
+        --set-default)
+            set_default="${2}"
+            shift
+            ;;
+        --set-default-index)
+            set_default="${2}"
+            shift
+            ;;
+        --title)
+            title="${2}"
+            shift
+            ;;
+        --update-kernel)
+            update_kernel="${2}"
+            shift
+            ;;
+        --zipl)
+            bootloader="zipl"
+            ;;
+        --bls-directory|-b)
+            blsdir="${2}"
+	    shift
+	    ;;
+        --add-kernel|--add-multiboot|--mbargs|--mounts|--boot-filesystem|\
+        --bootloader-probe|--debug|--devtree|--devtreedir|--elilo|--efi|\
+        --extlinux|--grub|--lilo|--output-file|--remove-mbargs|--silo|\
+        --remove-multiboot|--slilo|--yaboot)
+            echo
+            echo "${SCRIPTNAME}: the option \"${1}\" was deprecated" >&2
+            echo "Try '${SCRIPTNAME} --help' to list supported options" >&2
+            echo
+	    exit 1
+	    ;;
+        --)
+            shift
+            break
+            ;;
+        *)
+            echo
+            echo "${SCRIPTNAME}: invalid option \"${1}\"" >&2
+            echo "Try '${SCRIPTNAME} --help' for more information" >&2
+            echo
+            exit 1
+            ;;
+    esac
+    shift
+done
+
+if [[ -z $blsdir ]]; then
+    blsdir="/boot/loader/entries"
+fi
+
+if [[ -z $env ]]; then
+    env="/boot/grub2/grubenv"
+fi
+
+if [[ -z $zipl_config ]]; then
+    zipl_config="/etc/zipl.conf"
+fi
+
+get_bls_values
+
+default_index="$(get_default_index)"
+
+if [[ -n $display_default ]]; then
+    display_default_value
+fi
+
+if [[ -n $display_info ]]; then
+    display_info_values "${display_info}"
+fi
+
+if [[ $(get_prefix) == "/boot" ]]; then
+    remove_var_prefix
+fi
+
+if [[ -n $kernel ]]; then
+    if [[ $copy_default = "true" ]]; then
+	opts="${bls_options[$default_index]}"
+	if [[ -n $args ]]; then
+	    opts="${opts} ${args}"
+	fi
+    else
+	opts="${args}"
+    fi
+
+    add_bls_fragment "${kernel}" "${title}" "${opts}" "${initrd}" \
+                     "${extra_initrd}"
+fi
+
+if [[ -n $remove_kernel ]]; then
+    remove_bls_fragment "${remove_kernel}"
+fi
+
+if [[ -n $update_kernel ]]; then
+    update_bls_fragment "${update_kernel}" "${remove_args}" "${args}" "${initrd}"
+fi
+
+if [[ -n $set_default ]]; then
+    set_default_bls "${set_default}"
+fi
+
+exit 0
diff --git a/SOURCES/grubby.in b/SOURCES/grubby.in
new file mode 100644
index 0000000..f0036e9
--- /dev/null
+++ b/SOURCES/grubby.in
@@ -0,0 +1,8 @@
+#!/bin/bash
+if [[ -x @@LIBEXECDIR@@/grubby-bls ]] ; then
+	exec @@LIBEXECDIR@@/grubby-bls "${@}"
+elif [[ -x @@LIBEXECDIR@@/grubby ]] ; then
+	exec @@LIBEXECDIR@@/grubby "${@}"
+fi
+echo "Grubby is not installed correctly." >>/dev/stderr
+exit 1
diff --git a/SOURCES/installkernel-bls b/SOURCES/installkernel-bls
new file mode 100755
index 0000000..f2f607e
--- /dev/null
+++ b/SOURCES/installkernel-bls
@@ -0,0 +1,83 @@
+#! /bin/sh
+#
+# /sbin/installkernel
+#
+# Copyright 2007-2008 Red Hat, Inc.  All rights reserved.
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): tyson@rwii.com
+#
+
+usage() {
+    echo "Usage: `basename $0` <kernel_version> <bootimage> <mapfile>" >&2
+    exit 1
+}
+
+cfgLoader=
+
+if [ -z "$INSTALL_PATH" -o "$INSTALL_PATH" == "/boot" ]; then
+    INSTALL_PATH=/boot
+    cfgLoader=1
+fi
+
+LINK_PATH=/boot
+RELATIVE_PATH=`echo "$INSTALL_PATH/" | sed "s|^$LINK_PATH/||"`
+KERNEL_VERSION=$1
+BOOTIMAGE=$2
+MAPFILE=$3
+ARCH=$(uname -m)
+if [ $ARCH = 'ppc64' -o $ARCH = 'ppc' ]; then
+    KERNEL_NAME=vmlinux
+else
+    KERNEL_NAME=vmlinuz
+fi
+
+if [ -z "$KERNEL_VERSION" -o -z "$BOOTIMAGE" -o -z "$MAPFILE" ]; then
+    usage
+fi
+
+if [ -f $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION ]; then
+      mv $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION \
+              $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION.old;
+fi
+
+if [ ! -L $INSTALL_PATH/$KERNEL_NAME ]; then
+    if [ -e $INSTALLPATH/$KERNEL_NAME ]; then
+	mv $INSTALL_PATH/$KERNEL_NAME $INSTALL_PATH/$KERNEL_NAME.old
+    fi
+fi
+
+if [ -f $INSTALL_PATH/System.map-$KERNEL_VERSION ]; then
+      mv $INSTALL_PATH/System.map-$KERNEL_VERSION \
+              $INSTALL_PATH/System.map-$KERNEL_VERSION.old;
+fi
+
+if [ ! -L $INSTALL_PATH/System.map ]; then
+    if [ -e $INSTALLPATH/System.map ]; then
+	mv $INSTALL_PATH/System.map $INSTALL_PATH/System.map.old
+    fi
+fi
+ln -sf ${RELATIVE_PATH}$INSTALL_PATH/System.map-$KERNEL_VERSION $LINK_PATH/System.map
+
+cat $BOOTIMAGE > $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION
+cp $MAPFILE $INSTALL_PATH/System.map-$KERNEL_VERSION
+
+ln -fs ${RELATIVE_PATH}$INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION $LINK_PATH/$KERNEL_NAME
+ln -fs ${RELATIVE_PATH}$INSTALL_PATH/System.map-$KERNEL_VERSION $LINK_PATH/System.map
+
+if [ -n "$cfgLoader" ]; then
+	kernel-install add $KERNEL_VERSION $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION
+	exit $?
+fi
diff --git a/SOURCES/installkernel.in b/SOURCES/installkernel.in
new file mode 100644
index 0000000..87b81ee
--- /dev/null
+++ b/SOURCES/installkernel.in
@@ -0,0 +1,8 @@
+#!/bin/bash
+if [[ -x @@LIBEXECDIR@@/installkernel ]] ; then
+	exec @@LIBEXECDIR@@/installkernel "${@}"
+elif [[ -x @@LIBEXECDIR@@/installkernel-bls ]] ; then
+	exec @@LIBEXECDIR@@/installkernel-bls "${@}"
+fi
+echo "installkernel is not installed correctly." >>/dev/stderr
+exit 1
diff --git a/SPECS/grubby.spec b/SPECS/grubby.spec
new file mode 100644
index 0000000..a7cb388
--- /dev/null
+++ b/SPECS/grubby.spec
@@ -0,0 +1,650 @@
+Name: grubby
+Version: 8.40
+Release: 34%{?dist}
+Summary: Command line tool for updating BootLoaderSpec files
+License: GPLv2+
+URL: https://github.com/rhinstaller/grubby
+# we only pull git snaps at the moment
+# git clone git@github.com:rhinstaller/grubby.git
+# git archive --format=tar --prefix=grubby-%%{version}/ HEAD |bzip2 > grubby-%%{version}.tar.bz2
+# Source0: %%{name}-%%{version}.tar.bz2
+Source0: https://github.com/rhboot/grubby/archive/%{version}-1.tar.gz
+Source1: grubby-bls
+Source2: grubby.in
+Source3: installkernel.in
+Source4: installkernel-bls
+Patch0001: 0001-Set-envFile-from-env-when-bootloader-is-not-specifie.patch
+Patch0002: 0002-add-README-with-description-of-the-test-suite.patch
+Patch0003: 0003-Fix-some-stray-whitespace.patch
+Patch0004: 0004-grubby-properly-handle-mixed-and-and-nested-quotes.patch
+Patch0005: 0005-Don-t-put-spaces-in-debug-entries-on-zipl-platforms.patch
+Patch0006: 0006-Drop-SEGV-handler.patch
+Patch0007: 0007-Add-a-bunch-of-tests-for-various-default-kernel-titl.patch
+Patch0008: 0008-Emit-better-systemd-debug-settings-on-debug-entries.patch
+Patch0009: 0009-Add-a-new-makefile-target-that-does-everything-neede.patch
+Patch0010: 0010-Make-the-grub1-defaultkernel-test-more-reliable.patch
+Patch0011: 0011-Don-t-leak-from-one-extractTitle-call.patch
+Patch0012: 0012-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch
+Patch0013: 0013-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch
+Patch0014: 0014-Lindent-dammit.patch
+Patch0015: 0015-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch
+Patch0016: 0016-Specify-bootloader-directory-in-the-test-case-for-11.patch
+Patch0017: 0017-Fix-dracut-cmdline-options-and-conditionalize-them-t.patch
+Patch0018: 0018-Add-missing-space.patch
+Patch0019: 0019-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch
+Patch0020: 0020-grubby-add-set-index-to-specify-which-position-to-ad.patch
+Patch0021: 0021-Fix-thinko-on-set-index-naming.patch
+Patch0022: 0022-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch
+Patch0023: 0023-Ensure-command-line-updates-also-honor-set-index.patch
+Patch0024: 0024-Change-debug-entry-insertion-order-rhbz-1285601.patch
+Patch0025: 0025-Reorganize-grubby-man-page-1232168.patch
+Patch0026: 0026-Update-grubby-man-page-contents-bz1232168.patch
+Patch0027: 0027-Fix-inline-help-typo-1232168.patch
+Patch0028: 0028-More-edits-for-grubby.8-1232168.patch
+Patch0029: 0029-Minor-man-page-changes-1232168.patch
+Patch0030: 0030-Rename-setDefaultImage-variables.patch
+Patch0031: 0031-Add-index-constant-definitions-instead-of-open-coded.patch
+Patch0032: 0032-Track-configuration-modifications.patch
+Patch0033: 0033-Fix-some-test-cases-where-the-resulting-default-inde.patch
+Patch0034: 0034-Don-t-assume-make-default-just-because-set-index-was.patch
+Patch0035: 0035-Clarify-set-default-index-in-the-man-page.patch
+Patch0036: 0036-Add-multi-entry-removal-test-1285601.patch
+Patch0037: 0037-Fix-findTemplate-index-logic-1285601.patch
+Patch0038: 0038-Write-correct-default-to-environment-1285601.patch
+Patch0039: 0039-Initialize-variable-for-ppc-environment-1285601.patch
+Patch0040: 0040-Fix-initial-saved_entry-read-issue-1285601.patch
+Patch0041: 0041-Add-s390-s390x-info-test-1285601.patch
+Patch0042: 0042-Fix-info-for-s390x-s390-1285601.patch
+Patch0043: 0043-Add-s390-s390x-set-default-index-test-1285601.patch
+Patch0044: 0044-Fix-setDefaultImage-for-s390-s390x-1285601.patch
+Patch0045: 0045-Be-more-thorough-about-flushing-our-config-file-when.patch
+Patch0046: 0046-Fix-incorrect-test-case-and-remove-args-with-a-value.patch
+Patch0047: 0047-grubby-Make-sure-configure-BOOTLOADER-variables-are-.patch
+Patch0048: 0048-remove-the-old-crufty-u-boot-support.patch
+Patch0049: 0049-Change-return-type-in-getRootSpecifier.patch
+Patch0050: 0050-Add-btrfs-subvolume-support-for-grub2.patch
+Patch0051: 0051-Add-tests-for-btrfs-support.patch
+Patch0052: 0052-Use-system-LDFLAGS.patch
+Patch0053: 0053-Honor-sbindir.patch
+Patch0054: 0054-Make-installkernel-to-use-kernel-install-scripts-on-.patch
+Patch0055: 0055-Add-usr-libexec-rpm-sort.patch
+Patch0056: 0056-Improve-man-page-for-info-option.patch
+
+BuildRequires: gcc
+BuildRequires: pkgconfig glib2-devel popt-devel 
+BuildRequires: libblkid-devel git-core sed make
+# for make test / getopt:
+BuildRequires: util-linux-ng
+BuildRequires: rpm-devel
+%ifarch aarch64 i686 x86_64 %{power64}
+BuildRequires: grub2-tools-minimal
+Requires: grub2-tools-minimal
+Requires: grub2-tools
+%endif
+%ifarch s390 s390x
+Requires: s390utils-base
+%endif
+Requires: findutils
+
+%description
+This package provides a grubby compatibility script that manages
+BootLoaderSpec files and is meant to only be used for legacy compatibility
+users with existing grubby users.
+
+%prep
+%setup -q -n grubby-%{version}-1
+
+git init
+git config user.email "noone@example.com"
+git config user.name "no one"
+git add .
+git commit -a -q -m "%{version} baseline"
+git branch start
+git am %{patches} </dev/null
+git config --unset user.email
+git config --unset user.name
+
+%build
+%set_build_flags
+make %{?_smp_mflags} LDFLAGS="${LDFLAGS}"
+
+%ifnarch aarch64 %{arm}
+%check
+make test
+%endif
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} sbindir=%{_sbindir} libexecdir=%{_libexecdir}
+
+mkdir -p %{buildroot}%{_libexecdir}/{grubby,installkernel}/ %{buildroot}%{_sbindir}/
+mv -v %{buildroot}%{_sbindir}/grubby %{buildroot}%{_libexecdir}/grubby/grubby
+mv -v %{buildroot}%{_sbindir}/installkernel %{buildroot}%{_libexecdir}/installkernel/installkernel
+cp -v %{SOURCE1} %{buildroot}%{_libexecdir}/grubby/
+cp -v %{SOURCE4} %{buildroot}%{_libexecdir}/installkernel/
+sed -e "s,@@LIBEXECDIR@@,%{_libexecdir}/grubby,g" %{SOURCE2} \
+	> %{buildroot}%{_sbindir}/grubby
+sed -e "s,@@LIBEXECDIR@@,%{_libexecdir}/installkernel,g" %{SOURCE3} \
+	> %{buildroot}%{_sbindir}/installkernel
+
+%package deprecated
+Summary: Legacy command line tool for updating bootloader configs
+Conflicts:	%{name} <= 8.40-13
+
+%description deprecated
+This package provides deprecated, legacy grubby.  This is for temporary
+compatibility only.
+
+grubby is a command line tool for updating and displaying information about
+the configuration files for the grub, lilo, elilo (ia64), yaboot (powerpc)
+and zipl (s390) boot loaders. It is primarily designed to be used from
+scripts which install new kernels and need to find information about the
+current boot environment.
+
+%files
+%{!?_licensedir:%global license %%doc}
+%license COPYING
+%dir %{_libexecdir}/grubby
+%dir %{_libexecdir}/installkernel
+%attr(0755,root,root) %{_libexecdir}/grubby/grubby-bls
+%attr(0755,root,root) %{_libexecdir}/grubby/rpm-sort
+%attr(0755,root,root) %{_sbindir}/grubby
+%attr(0755,root,root) %{_libexecdir}/installkernel/installkernel-bls
+%attr(0755,root,root) %{_sbindir}/installkernel
+%{_mandir}/man8/[gi]*.8*
+
+%files deprecated
+%{!?_licensedir:%global license %%doc}
+%license COPYING
+%dir %{_libexecdir}/grubby
+%dir %{_libexecdir}/installkernel
+%attr(0755,root,root) %{_libexecdir}/grubby/grubby
+%attr(0755,root,root) %{_libexecdir}/installkernel/installkernel
+%attr(0755,root,root) %{_sbindir}/grubby
+%attr(0755,root,root) %{_sbindir}/installkernel
+%attr(0755,root,root) %{_sbindir}/new-kernel-pkg
+%{_mandir}/man8/*.8*
+
+%changelog
+* Wed Dec 19 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-34
+- grubby-bls: expand all variables in options field when updating it
+  Resolves: rhbz#1660700
+
+* Tue Dec 18 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-33
+- Correctly set LDFLAGS to include hardened flags (pjones)
+  Related: rhbz#1654936
+
+* Tue Dec 04 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-32
+- grubby-bls: lookup default entry by either id or title on grub2
+  Related: rhbz#1654936
+
+* Fri Nov 23 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-31
+- grubby-bls: allow to specify the same kernel param multiple times
+  Resolves: rhbz#1652486
+- grubby-bls: expand kernel options if these are environment variables
+  Resolves: rhbz#1649785
+- grubby-bls: always generate the BLS snippets when adding new entries
+  Resolves: rhbz#1653365
+- Improve man page for --info option (jstodola)
+  Resolves: rhbz#1651672
+
+* Tue Nov 20 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-30
+- grubby-bls: also print the absolute path in the --default-kernel option
+  Resolves: rhbz#1649778
+
+* Mon Nov 19 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-29
+- grubby-bls: print the absolute kernel and initramfs images paths
+  Resolves: rhbz#1649778
+- grubby-bls: make info print the root parameter if is present in cmdline
+  Resolves: rhbz#1649791
+
+* Mon Nov 12 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-28
+- grubby-bls: use title field instead of version for zipl default entry
+  Related: rhbz#1645200
+
+* Thu Nov 08 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-27
+- installkernel-bls: remove unnecessary check for GRUB_ENABLE_BLSCFG=true
+  Resolves: rhbz#1647721
+
+* Mon Nov 05 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-26
+- grubby-bls: only compare using relative paths if /boot is a mount point
+  Resolves: rhbz#1642078
+
+* Wed Oct 31 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-25
+- grubby-bls: fix --default-* options for s390x
+  Resolves: rhbz#1644608
+
+* Fri Oct 26 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-24
+- grubby-bls: allow to add many BLS entries for the same kernel image
+  Resolves: rhbz#1634752
+
+* Fri Oct 19 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-23
+- grubby-bls: use ~debug instead of -debug as suffix to sort correctly
+  Related: rhbz#1638103
+
+* Fri Oct 19 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-22
+- grubby-bls: grubby-bls: use id instead of title to get the default entry
+  Resolves: rhbz#1638103
+
+* Wed Oct 17 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-21
+- grubby-bls: escape delimiter character before replacing the options field
+  Resolves: rhbz#1640017
+
+* Tue Oct 16 2018 Peter Jones <pjones@redhat.com> - 8.40-20
+- Add missing patches from RHEL-7 for grubby-deprecated.
+  Resolves: rhbz#1561919
+- grubby-bls: make a copy of the cmdline if is modified for an entry
+  Resolves: rhbz#1629054
+
+* Mon Oct 15 2018 Peter Jones <pjones@redhat.com> - 8.40-19
+- grubby-bls: Make grubby-bls sort everything the same way grub2 does
+  Resolves: rhbz#1638103
+- grubby-bls: Consistently use the filename as the bls id
+  Related: rhbz#1638103
+- grubby-bls: check if entry exists before attempting to print its info
+  Resolves: rhbz#1634712
+
+* Thu Oct 11 2018 Peter Jones <pjones@redhat.com> - 8.40-18
+- grubby-bls: make "id" be the filename, and include it in --info=ALL
+  Related: rhbz#1638103
+
+* Fri Oct 05 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-17
+- grubby-bls should only check if kernel exists and not if was installed
+  Resolves: rhbz#1634740
+- Use ! instead of , as sed delimiter in grubby-bls script
+  Resolves: rhbz#1634744
+- Print information about the entry set as default
+  Resolves: rhbz#1636180
+
+* Thu Oct 04 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-16
+- Make grubby-bls execute grub2-mkconfig on ppc64
+  Resolves: rhbz#1636039
+
+* Fri Sep 28 2018 Peter Jones <pjones@redhat.com> - 8.40-15
+- Install installkernel-bls here as well, not just in the grub2 package,
+  since s390x doesn't have grubby packages.
+  Related: rhbz#1619344
+
+* Fri Sep 28 2018 Peter Jones <pjones@redhat.com> - 8.40-14
+- Re-enable debuginfo generation.
+  Related: rhbz#1619344
+
+* Fri Aug 31 2018 Peter Jones <pjones@redhat.com> - 8.40-13
+- Make the temporary config wrapper be what "grubby" contains, and put
+  traditional grubby in grubby-deprecated.
+
+* Tue Apr 10 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-12
+- Use .rpmsave as backup suffix when switching to BLS configuration
+
+* Fri Apr 06 2018 Javier Martinez Canillas <javierm@redhat.com> - 8.40-11
+- Switch grub2 config to BLS configuration on %%postun
+
+* Sat Mar 03 2018 Nathaniel McCallum <npmccallum@redhat.com> - 8.40-10
+- Add support for /boot on btrfs subvolumes
+
+* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-9
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Wed Jan 24 2018 Peter Robinson <pbrobinson@fedoraproject.org> 8.40-8
+- Drop u-boot uImage generation on ARMv7
+- Minor cleanups
+
+* Tue Sep 12 2017 Peter Jones <pjones@redhat.com> - 8.40-7
+- Explicitly require grub2-tools on platforms that need grub2-editenv
+- Minor packaging cleanups
+
+* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
+
+* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.40-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Wed Apr 15 2015 Peter Jones <pjones@redhat.com> - 8.40-1
+- Update to 8.40
+- More work on the thing that went to testing in 8.39
+  Resolves: rhbz#1211887
+
+* Tue Apr 14 2015 Peter Jones <pjones@redhat.com> - 8.39-1
+- Update to 8.39
+- Fix title extraction with some config file types
+  Resolves: rhbz#1204353
+  Resolves: rhbz#1204888
+  Resolves: rhbz#1206943
+
+* Tue Apr 14 2015 Peter Jones <pjones@redhat.com> - 8.38-1
+- Update to 8.38
+- Fix title extraction with some config file types
+  Resolves: rhbz#1204353
+  Resolves: rhbz#1204888
+  Resolves: rhbz#1206943
+
+* Tue Mar 17 2015 Peter Jones <pjones@redhat.com> - 8.37-1
+- Update to 8.37
+- Fix test case from 8.35 on ppc64
+  Resolves: rhbz#1202876
+
+* Thu Nov 13 2014 Peter Jones <pjones@redhat.com> - 8.35-9
+- Disable "make check" on arm builds; right now the test suite is broken
+  there and raises false positives constantly.
+
+* Mon Oct 27 2014 Peter Jones <pjones@redhat.com> - 8.35-8
+- Treat kernel and kernel-core as identical in terms of --make-default
+  Resolves: rhbz#1141414
+
+* Thu Oct 16 2014 Peter Jones <pjones@redhat.com> - 8.35-7
+- Revert "debug" image creation for now
+  Resolves: rhbz#1153410
+- Fix minor quoting errors in dtbdir code
+  Resolves: rhbz#1088933
+
+* Wed Oct 15 2014 Peter Jones <pjones@redhat.com> - 8.35-6
+- Update grubby to support device tree options for arm.  Again.
+  Resolves: rhbz#1088933
+
+* Fri Sep 26 2014 Peter Jones <pjones@redhat.com> - 8.35-5
+- See if what people are seeing in 1141414 is actually 957681
+  Related: rhbz#957681
+  Related: rhbz#1141414
+
+* Sat Aug 16 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.35-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Sat Jul 12 2014 Tom Callaway <spot@fedoraproject.org> - 8.35-3
+- fix license handling
+
+* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.35-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Wed May 21 2014 Peter Jones <pjones@redhat.com> - 8.35-1
+- Fix a minor test case error that causes koji builds to fail.
+  Related: rhbz#1096358
+
+* Wed May 21 2014 Peter Jones <pjones@redhat.com> - 8.34-1
+- Make grub2 "--copy-default --add-kernel=foo --initrd=bar" work when default
+  has no initrd line.
+  Resolves: rhbz#1099627
+  Related: rhbz#1096358
+
+* Tue Apr 01 2014 Peter Jones <pjones@redhat.com> - 8.33-1
+- Fix --devtree test in new-kernel-pkg even harder (#1082318)
+
+* Mon Mar 31 2014 Peter Jones <pjones@redhat.com> - 8.32-1
+- Fix --devtree test in new-kernel-pkg (#1082318)
+- Fix aarch64 #define test.
+
+* Fri Mar 28 2014 Peter Jones <pjones@redhat.com> - 8.31-1
+- Update to 8.31
+- Fold in patches from Fedora and RHEL 7 trees
+
+* Mon Jan 20 2014 Lubomir Rintel <lkundrak@v3.sk> - 8.28-2
+- Fix extlinux default
+
+* Fri Aug 02 2013 Peter Jones <pjones@redhat.com> - 8.28-1
+- More work on grub's "saved_entry" system. 
+  Resolves: rhbz#768106
+  Resolves: rhbz#736188
+
+* Tue Jul 30 2013 Peter Jones <pjones@redhat.com> - 8.27-1
+- Make grubby understand grub's "saved_entry" system
+  Resolves: rhbz#768106
+  Resolves: rhbz#736188
+- BuildRequire grub2 on appropriate platforms, for the test suite.
+
+* Fri Jun 07 2013 Dennis Gilmore <dennis@ausil.us> - 8.26-2
+- add patch to update extlinux.conf file on arm if it exists
+
+* Fri May 10 2013 Peter Jones <pjones@redhat.com> - 8.26-1
+- Conditionally call arm-boot-config's boot.scr generator if available
+  Resolves: rhbz#952428
+
+* Tue Apr 09 2013 Peter Jones <pjones@redhat.com> - 8.25-1
+- Error instead of segfaulting if we can't find any working config
+  Resolves: rhbz#912873
+  Resolves: rhbz#751608
+
+* Tue Mar 19 2013 Peter Jones <pjones@redhat.com> - 8.24-1
+- Fix module remove code from Harald (#923441)
+
+* Mon Mar 11 2013 Peter Jones <pjones@redhat.com> - 8.23-1
+- Update to 8.23
+- Fix empty root device in case of an empty /etc/fstab (lemenkov)
+- General refactoring and cleanup (harald)
+- Don't clean up modules.* so aggressively (harald)
+
+* Wed Feb 20 2013 Peter Jones <pjones@redhat.com> - 8.22-3
+- Add --debug style logging (for both success and failures) to /var/log/grubby
+
+* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.22-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Fri Jan 04 2013 Peter Jones <pjones@redhat.com> - 8.22-1
+- Revert test case for rhbz#742885 - it's a work in progress that isn't
+  ready yet.
+
+* Fri Jan 04 2013 Peter Jones <pjones@redhat.com> - 8.21-1
+- Use systemd vconsole.conf and locale.conf if present
+  Resolves rhbz#881908
+- Avoid unnecessary stat calls (from Ville Skyttä)
+  Resolves rhbz#741135
+- Spelling fixes (Ville Skyttä)
+- Add a test case for rhbz#742885
+- Handle case-insensitive extlinux config files properly (from Johannes Weiner)
+
+* Tue Oct 02 2012 Peter Jones <pjones@redhat.com> - 8.20-1
+- Handle linuxefi initrd and removal correctly.
+  Resolves: rhbz#859285
+
+* Wed Sep 26 2012 Peter Jones <pjones@redhat.com> - 8.19-1
+- Don't accidentally migrate from linuxefi back to linux
+  Related: rhbz#859285
+
+* Fri Sep 21 2012 Peter Jones <pjones@redhat.com> - 8.18-1
+- Change the way the kernel load address is determined for ARM U-Boot.
+
+* Wed Aug 08 2012 Peter Jones <pjones@redhat.com> - 8.17-1
+- Update to 8.17
+- Fixes a "make test" failure.
+
+* Wed Aug 08 2012 Peter Jones <pjones@redhat.com> - 8.16-1
+- Update to 8.16
+- Handle "linuxefi" directive on grub2/uefi machines.
+
+* Thu Jul 19 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.15-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Mon Jun 25 2012 Peter Jones <pjones@redhat.com> - 8.15-1
+- Update to 8.15
+- Revert dirname change from 8.13; it was wrong.
+
+* Thu Jun 14 2012 Peter Jones <pjones@redhat.com> - 8.14-1
+- Update to 8.14 to fix a build problem.
+
+* Thu Jun 14 2012 Peter Jones <pjones@redhat.com> - 8.13-1
+- Update to 8.13
+- Add some more ARM tweaks (dmartin)
+- Better support for other distros (crosa)
+
+* Tue Jun 12 2012 Peter Jones <pjones@redhat.com> - 8.12-2
+- Support UBOOT_IMGADDR override on ARM (blc)
+
+* Thu May 31 2012 Peter Jones <pjones@redhat.com> - 8.12-1
+- Update to 8.12
+- Preserve trailing indentation when splitting line elements (mads)
+  Resolves: rhbz#742720
+- Pick last device mounted on / (pjones,bcl)
+  Related: rhbz#820340
+  Related: rhbz#820351
+
+* Wed Mar 21 2012 Peter Jones <pjones@redhat.com> - 8.11-1
+- Update to 8.11
+  Resolves: rhbz#805310
+
+* Thu Mar 15 2012 Peter Jones <pjones@redhat.com> - 8.10-1
+- Update to 8.10
+- Use "isquote" where appropriate
+- Make --remove-kenrel support titles in grub2 (jianzhong.huang)
+- Use grub2 if it's there on ppc.
+
+* Fri Mar 02 2012 Peter Jones <pjones@redhat.com> - 8.9-1
+- Refactor grub2 title extraction, making it a function (Cleber Rosa)
+- Include prefix when printing kernel information (Cleber Rosa)
+- Implement support for "default saved" for grub2 (Cleber Rosa)
+- Try to display title when printing information with '--info' (Cleber Rosa)
+- new-kernel-pkg fails to find U-Boot. (D. Marlin)
+- Add support to new-kernel-pkg to recognize ARCH == armv5tel needed for Kir
+  (D.Marlin)
+- Include a / when one is missing in paths (#769641)
+- Fix hard coded paths so kernel's "make install" will DTRT.
+- Fix endswith() to correctly test its input for validity.
+
+* Tue Feb 07 2012 Dennis Gilmore <dennis@ausil.us> - 8.8-3
+- add uboot-tools requires on arm arches
+- add uboot config file on arm arches
+
+* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 8.8-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Tue Dec 20 2011 Peter Jones <pjones@redhat.com> - 8.8-1
+- Fix test cases from 8.7 to work on a system without /boot mounted.
+
+* Tue Dec 20 2011 Peter Jones <pjones@redhat.com> - 8.7-1
+- Add a --debug to try to help diagnose "No suitable template". (sandeen,pjones)
+
+* Mon Dec 19 2011 Peter Jones <pjones@redhat.com> - 8.6-1
+- Fix a "make test" errors introduced in 8.4-1
+
+* Sat Dec 17 2011 Peter Jones <pjones@redhat.com> - 8.5-1
+- Don't hardcode dracut path
+  Resolves: #768645
+
+* Thu Dec 08 2011 Adam Williamson <awilliam@redhat.com> - 8.4-1
+- Update to 8.4:
+	+ fix Loading... line for updated kernels
+	+ Add new '--default-title' feature
+	+ Add new '--default-index' feature
+	+ add feature for testing the output of a grubby command
+	+ Fix detection when comparing stage1 to MBR
+	+ do not link against glib-2.0
+	+ Don't crash if grubConfig not found
+	+ Adding extlinux support for new-kernel-pkg
+	+ Look for Debian / Ubuntu grub config files (#703260)
+	+ Make grubby recognize Ubuntu's spin of Grub2 (#703260)
+
+* Thu Sep 29 2011 Peter Jones <pjones@redhat.com> - 8.3-1
+- Fix new-kernel-pkg invocation of grubby for grub (patch from Mads Kiilerich)
+  Resolves: rhbz#725185
+
+* Wed Sep 14 2011 Peter Jones <pjones@redhat.com> - 8.2-1
+- Fixes for xen (from Michael Petullo)
+  Resolves: rhbz#658387
+
+* Fri Jul 22 2011 Peter Jones <pjones@redhat.com> - 8.1-1
+- Update to 8.1
+- Fix miss-spelled variable name in new-kernel-pkg
+
+* Thu Jul 21 2011 Peter Jones <pjones@redhat.com> - 8.0-1
+- Add support for grub2.
+
+* Tue Jun 07 2011 Brian C. Lane <bcl@redhat.com> - 7.0.18-1
+- Bump version to 7.0.18 (bcl)
+- Fixup new-kernel-pkg errors (#711493) (bcl)
+
+* Mon Jun 06 2011 Peter Jones <pjones@redhat.com> - 7.0.17-1
+- Fix references to wrong program name in new-kernel-pkg.8
+  Resolves: rhbz#663981
+
+* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 7.0.16-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Mon Jan 24 2011 Karsten Hopp <karsten@redhat.com> 7.0.16-2
+- add BR utils-linux-ng for getopt
+
+* Tue Jul 13 2010 Brian C. Lane <bcl@redhat.com> - 7.0.16-1
+- Update to 7.0.16
+- Add patch to check the return value of getuuidbydev
+- Resolves: rhbz#592294
+
+* Wed Apr 14 2010 Peter Jones <pjones@redhat.com> - 7.0.15-1
+- Update to 7.0.15
+- Add man pages for installkernel and new-kernel-pkg
+  Resolves: rhbz#529333
+
+* Wed Apr 14 2010 Peter Jones <pjones@redhat.com> - 7.0.14-1
+- Update to 7.0.14
+
+* Thu Feb 11 2010 Peter Jones <pjones@redhat.com> - 7.0.13-1
+- Strip boot partition prefix from initrd path if present during --update.
+  Related: rhbz#557922
+- add host only support for local kernel compiles (airlied)
+
+* Mon Feb 08 2010 Peter Jones <pjones@redhat.com> - 7.0.12-1
+- compare rootdev using uuid instead of stat, for better btrfs support (josef)
+  Resolves: rhbz#530108
+
+* Mon Feb 08 2010 Peter Jones <pjones@redhat.com> - 7.0.11-1
+- Make it possible to update the initrd without any other change.
+  Related: rhbz#557922
+
+* Fri Feb 05 2010 Peter Jones <pjones@redhat.com> - 7.0.10-1
+- Make --update able to add an initramfs.
+  Related: rhbz#557922
+
+* Mon Nov 30 2009 Peter Jones <pjones@redhat.com> - 7.0.9-3
+- Use s390utils-base as the s390 dep, not s390utils
+  Related: rhbz#540565
+
+* Tue Nov 24 2009 Peter Jones <pjones@redhat.com> - 7.0.9-2
+- Add s390utils dep when on s390, since new-kernel-package needs it.
+  Resolves: rhbz#540565
+
+* Fri Oct 30 2009 Peter Jones <pjones@redhat.com> - 7.0.9-1
+- Add support for dracut to installkernel (notting)
+
+* Thu Oct  1 2009 Hans de Goede <hdegoede@redhat.com> - 7.0.8-1
+- Stop using nash
+
+* Fri Sep 11 2009 Hans de Goede <hdegoede@redhat.com> - 7.0.7-1
+- Remove writing rd_plytheme=$theme to kernel args in dracut mode (hansg)
+- Add a couple of test cases for extra initrds (rstrode)
+- Allow tmplLine to be NULL in getInitrdVal (rstrode)
+
+* Fri Sep 11 2009 Peter Jones <pjones@redhat.com> - 7.0.6-1
+- Fix test case breakage from 7.0.5 (rstrode)
+
+* Fri Sep 11 2009 Peter Jones <pjones@redhat.com> - 7.0.5-1
+- Add support for plymouth as a second initrd. (rstrode)
+  Resolves: rhbz#520515
+
+* Wed Sep 09 2009 Hans de Goede <hdegoede@redhat.com> - 7.0.4-1
+- Add --dracut cmdline argument for %%post generation of dracut initrd
+
+* Wed Aug 26 2009 Hans de Goede <hdegoede@redhat.com> - 7.0.3-1
+- Silence error when no /etc/sysconfig/keyboard (#517187)
+
+* Fri Aug  7 2009 Hans de Goede <hdegoede@redhat.com> - 7.0.2-1
+- Add --add-dracut-args new-kernel-pkg cmdline option
+
+* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 7.0.1-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Fri Jul 17 2009 Jeremy Katz <katzj@redhat.com> - 7.0.1-1
+- Fix blkid usage (#124246)
+
+* Wed Jun 24 2009 Jeremy Katz <katzj@redhat.com> - 7.0-1
+- BR libblkid-devel now instead of e2fsprogs-devel
+- Add bits to switch to using dracut for new-kernel-pkg
+
+* Wed Jun  3 2009 Jeremy Katz <katzj@redhat.com> - 6.0.86-2
+- add instructions for checking out from git
+
+* Tue Jun  2 2009 Jeremy Katz <katzj@redhat.com> - 6.0.86-1
+- initial build after splitting out from mkinitrd
+