From db9dcccb9eae427c5b3f2f5ab5dd18ccf49f4055 Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Fri, 29 Mar 2024 15:44:06 +0300 Subject: [PATCH] import grubby-8.40-49.el8 --- .gitignore | 1 + .grubby.metadata | 1 + ...-env-when-bootloader-is-not-specifie.patch | 30 + ...E-with-description-of-the-test-suite.patch | 91 + SOURCES/0003-Fix-some-stray-whitespace.patch | 35 + ...y-handle-mixed-and-and-nested-quotes.patch | 162 + ...s-in-debug-entries-on-zipl-platforms.patch | 34 + SOURCES/0006-Drop-SEGV-handler.patch | 52 + ...ests-for-various-default-kernel-titl.patch | 183 + ...temd-debug-settings-on-debug-entries.patch | 28 + ...le-target-that-does-everything-neede.patch | 25 + ...ub1-defaultkernel-test-more-reliable.patch | 41 + ...on-t-leak-from-one-extractTitle-call.patch | 85 + ...ync-grub.cfg-changes-to-disk-1212114.patch | 42 + ...-to-run-test.sh-verbose-from-the-mak.patch | 38 + SOURCES/0014-Lindent-dammit.patch | 9239 +++++++++++++++++ ...E-get-handled-individually-in-GetNex.patch | 586 ++ ...er-directory-in-the-test-case-for-11.patch | 31 + ...ne-options-and-conditionalize-them-t.patch | 63 + SOURCES/0018-Add-missing-space.patch | 25 + ...ngrubby-debug-after-the-normal-kerne.patch | 123 + ...ndex-to-specify-which-position-to-ad.patch | 298 + .../0021-Fix-thinko-on-set-index-naming.patch | 37 + ...for-a-failure-rmarshall-saw-in-set-i.patch | 386 + ...nd-line-updates-also-honor-set-index.patch | 46 + ...g-entry-insertion-order-rhbz-1285601.patch | 67 + ...5-Reorganize-grubby-man-page-1232168.patch | 356 + ...e-grubby-man-page-contents-bz1232168.patch | 369 + .../0027-Fix-inline-help-typo-1232168.patch | 29 + ...0028-More-edits-for-grubby.8-1232168.patch | 213 + .../0029-Minor-man-page-changes-1232168.patch | 36 + ...030-Rename-setDefaultImage-variables.patch | 66 + ...nt-definitions-instead-of-open-coded.patch | 198 + ...32-Track-configuration-modifications.patch | 50 + ...ses-where-the-resulting-default-inde.patch | 65 + ...e-default-just-because-set-index-was.patch | 197 + ...fy-set-default-index-in-the-man-page.patch | 32 + ...Add-multi-entry-removal-test-1285601.patch | 261 + ...Fix-findTemplate-index-logic-1285601.patch | 40 + ...rrect-default-to-environment-1285601.patch | 43 + ...variable-for-ppc-environment-1285601.patch | 29 + ...itial-saved_entry-read-issue-1285601.patch | 64 + ...041-Add-s390-s390x-info-test-1285601.patch | 74 + ...0042-Fix-info-for-s390x-s390-1285601.patch | 59 + ...s390x-set-default-index-test-1285601.patch | 59 + ...tDefaultImage-for-s390-s390x-1285601.patch | 32 + ...-about-flushing-our-config-file-when.patch | 78 + ...st-case-and-remove-args-with-a-value.patch | 168 + ...-configure-BOOTLOADER-variables-are-.patch | 59 + ...remove-the-old-crufty-u-boot-support.patch | 237 + ...ange-return-type-in-getRootSpecifier.patch | 148 + ...dd-btrfs-subvolume-support-for-grub2.patch | 208 + .../0051-Add-tests-for-btrfs-support.patch | 1871 ++++ SOURCES/0052-Use-system-LDFLAGS.patch | 24 + SOURCES/0053-Honor-sbindir.patch | 36 + ...el-to-use-kernel-install-scripts-on-.patch | 48 + SOURCES/0055-Add-usr-libexec-rpm-sort.patch | 419 + ...056-Improve-man-page-for-info-option.patch | 30 + SOURCES/grubby-bls | 836 ++ SOURCES/grubby.8 | 179 + SOURCES/grubby.in | 8 + SOURCES/installkernel-bls | 83 + SOURCES/installkernel.in | 8 + SPECS/grubby.spec | 736 ++ 64 files changed, 19197 insertions(+) create mode 100644 .gitignore create mode 100644 .grubby.metadata create mode 100644 SOURCES/0001-Set-envFile-from-env-when-bootloader-is-not-specifie.patch create mode 100644 SOURCES/0002-add-README-with-description-of-the-test-suite.patch create mode 100644 SOURCES/0003-Fix-some-stray-whitespace.patch create mode 100644 SOURCES/0004-grubby-properly-handle-mixed-and-and-nested-quotes.patch create mode 100644 SOURCES/0005-Don-t-put-spaces-in-debug-entries-on-zipl-platforms.patch create mode 100644 SOURCES/0006-Drop-SEGV-handler.patch create mode 100644 SOURCES/0007-Add-a-bunch-of-tests-for-various-default-kernel-titl.patch create mode 100644 SOURCES/0008-Emit-better-systemd-debug-settings-on-debug-entries.patch create mode 100644 SOURCES/0009-Add-a-new-makefile-target-that-does-everything-neede.patch create mode 100644 SOURCES/0010-Make-the-grub1-defaultkernel-test-more-reliable.patch create mode 100644 SOURCES/0011-Don-t-leak-from-one-extractTitle-call.patch create mode 100644 SOURCES/0012-ppc64le-sync-grub.cfg-changes-to-disk-1212114.patch create mode 100644 SOURCES/0013-Make-it-possible-to-run-test.sh-verbose-from-the-mak.patch create mode 100644 SOURCES/0014-Lindent-dammit.patch create mode 100644 SOURCES/0015-Make-SET_VARIABLE-get-handled-individually-in-GetNex.patch create mode 100644 SOURCES/0016-Specify-bootloader-directory-in-the-test-case-for-11.patch create mode 100644 SOURCES/0017-Fix-dracut-cmdline-options-and-conditionalize-them-t.patch create mode 100644 SOURCES/0018-Add-missing-space.patch create mode 100644 SOURCES/0019-Always-do-the-rungrubby-debug-after-the-normal-kerne.patch create mode 100644 SOURCES/0020-grubby-add-set-index-to-specify-which-position-to-ad.patch create mode 100644 SOURCES/0021-Fix-thinko-on-set-index-naming.patch create mode 100644 SOURCES/0022-Add-a-test-case-for-a-failure-rmarshall-saw-in-set-i.patch create mode 100644 SOURCES/0023-Ensure-command-line-updates-also-honor-set-index.patch create mode 100644 SOURCES/0024-Change-debug-entry-insertion-order-rhbz-1285601.patch create mode 100644 SOURCES/0025-Reorganize-grubby-man-page-1232168.patch create mode 100644 SOURCES/0026-Update-grubby-man-page-contents-bz1232168.patch create mode 100644 SOURCES/0027-Fix-inline-help-typo-1232168.patch create mode 100644 SOURCES/0028-More-edits-for-grubby.8-1232168.patch create mode 100644 SOURCES/0029-Minor-man-page-changes-1232168.patch create mode 100644 SOURCES/0030-Rename-setDefaultImage-variables.patch create mode 100644 SOURCES/0031-Add-index-constant-definitions-instead-of-open-coded.patch create mode 100644 SOURCES/0032-Track-configuration-modifications.patch create mode 100644 SOURCES/0033-Fix-some-test-cases-where-the-resulting-default-inde.patch create mode 100644 SOURCES/0034-Don-t-assume-make-default-just-because-set-index-was.patch create mode 100644 SOURCES/0035-Clarify-set-default-index-in-the-man-page.patch create mode 100644 SOURCES/0036-Add-multi-entry-removal-test-1285601.patch create mode 100644 SOURCES/0037-Fix-findTemplate-index-logic-1285601.patch create mode 100644 SOURCES/0038-Write-correct-default-to-environment-1285601.patch create mode 100644 SOURCES/0039-Initialize-variable-for-ppc-environment-1285601.patch create mode 100644 SOURCES/0040-Fix-initial-saved_entry-read-issue-1285601.patch create mode 100644 SOURCES/0041-Add-s390-s390x-info-test-1285601.patch create mode 100644 SOURCES/0042-Fix-info-for-s390x-s390-1285601.patch create mode 100644 SOURCES/0043-Add-s390-s390x-set-default-index-test-1285601.patch create mode 100644 SOURCES/0044-Fix-setDefaultImage-for-s390-s390x-1285601.patch create mode 100644 SOURCES/0045-Be-more-thorough-about-flushing-our-config-file-when.patch create mode 100644 SOURCES/0046-Fix-incorrect-test-case-and-remove-args-with-a-value.patch create mode 100644 SOURCES/0047-grubby-Make-sure-configure-BOOTLOADER-variables-are-.patch create mode 100644 SOURCES/0048-remove-the-old-crufty-u-boot-support.patch create mode 100644 SOURCES/0049-Change-return-type-in-getRootSpecifier.patch create mode 100644 SOURCES/0050-Add-btrfs-subvolume-support-for-grub2.patch create mode 100644 SOURCES/0051-Add-tests-for-btrfs-support.patch create mode 100644 SOURCES/0052-Use-system-LDFLAGS.patch create mode 100644 SOURCES/0053-Honor-sbindir.patch create mode 100644 SOURCES/0054-Make-installkernel-to-use-kernel-install-scripts-on-.patch create mode 100644 SOURCES/0055-Add-usr-libexec-rpm-sort.patch create mode 100644 SOURCES/0056-Improve-man-page-for-info-option.patch create mode 100755 SOURCES/grubby-bls create mode 100644 SOURCES/grubby.8 create mode 100644 SOURCES/grubby.in create mode 100755 SOURCES/installkernel-bls create mode 100644 SOURCES/installkernel.in create mode 100644 SPECS/grubby.spec 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" +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 +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 +Date: Wed, 24 Jun 2015 09:20:35 -0400 +Subject: [PATCH 03/55] Fix some stray whitespace + +Signed-off-by: Peter Jones +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +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 +--- + 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 +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 +--- + 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 +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 +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 +--- + 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 +Date: Tue, 18 Aug 2015 10:43:39 -0400 +Subject: [PATCH 14/55] Lindent, dammit. + +Signed-off-by: Peter Jones +--- + 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, ©Default, 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, ©Default, 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 +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 +--- + 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 +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 +--- + 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 +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 +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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +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 +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 +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 +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 + +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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, ¤tLookupIndex); ++ } ++ /* 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 +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 +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 +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 +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?= +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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +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 +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 +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 +Date: Wed, 18 Jul 2018 13:41:02 -0400 +Subject: [PATCH 53/55] Honor sbindir + +Signed-off-by: Peter Jones +--- + 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 +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 +Signed-off-by: Javier Martinez Canillas +--- + 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` " >&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 +Date: Fri, 12 Oct 2018 16:39:37 -0400 +Subject: [PATCH 55/55] Add /usr/libexec/rpm-sort + +Signed-off-by: Peter Jones +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 +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..07df5c8 --- /dev/null +++ b/SOURCES/grubby-bls @@ -0,0 +1,836 @@ +#!/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 . + +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 2>/dev/null | 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 ]] && mountpoint -q /boot; 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 +} + +has_kernelopts() +{ + local args=${bls_options[$1]} + local opts=(${args}) + + for opt in ${opts[*]}; do + [[ $opt = "\$kernelopts" ]] && echo "true" + done + + echo "false" +} + +get_bls_args() { + local args=${bls_options[$1]} + local opts=(${args}) + + for opt in ${opts[*]}; do + if [[ $opt = "\$kernelopts" ]]; 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 < "${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 + arg="$(echo $arg | sed -e 's/\//\\\//g')" + if [[ $arg = *"="* ]]; then + 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%%=*}" + arg="$(echo $arg | sed -e 's/\//\\\//g')" + 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 param="$1" + local indexes=($(param_to_indexes "$1")) && shift + local remove_args=$1 && shift + local add_args=$1 && shift + local initrd=$1 && shift + local opts + + if [[ $indexes = "-1" ]]; then + print_error "The param $(get_prefix)${param} is incorrect" + fi + + if [[ $param = "ALL" && $bootloader = grub2 ]] && [[ -n $remove_args || -n $add_args ]]; then + local old_args="" + + if [[ -z $no_etc_update ]] && [[ -e ${grub_etc_default} ]]; then + old_args="$(source ${grub_etc_default}; echo ${GRUB_CMDLINE_LINUX})" + if [[ -n $old_args ]]; then + opts="$(update_args "${old_args}" "${remove_args}" "${add_args}")" + opts="$(echo "$opts" | sed -e 's/\//\\\//g')" + sed -i -e "s/^GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\\\"${opts}\\\"/" "${grub_etc_default}" + fi + fi + + old_args="$(grub2-editenv "${env}" list | grep kernelopts | sed -e "s/kernelopts=//")" + if [[ -n $old_args ]]; then + opts="$(update_args "${old_args}" "${remove_args}" "${add_args}")" + grub2-editenv "${env}" set kernelopts="${opts}" + fi + elif [[ $bootloader = grub2 ]]; then + opts="$(grub2-editenv "${env}" list | grep kernelopts | sed -e "s/kernelopts=//")" + 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}")" + + if [[ $param != "ALL" || "$(has_kernelopts "$i")" = "false" ]]; then + set_bls_value "${bls_file[$i]}" "options" "${new_args}" + fi + + if [[ $bootloader = grub2 && "$(has_kernelopts "$i")" = "false" && $opts = $new_args ]]; then + set_bls_value "${bls_file[$i]}" "options" "\$kernelopts" + fi + fi + + if [[ -n $initrd ]]; then + set_bls_value "${bls_file[$i]}" "initrd" "${initrd}" + fi + done + + if [[ $param = "ALL" ]] && [[ -n $remove_args || -n $add_args ]]; then + if [[ ! -f /etc/kernel/cmdline ]]; then + # anaconda could pre-populate this file, but until then, most of + # the time we'll just want the most recent one. This is pretty + # close to the current almost-correct behavior of falling back to + # /proc/cmdline anyhow. + echo "$(get_bls_args -1)" > /etc/kernel/cmdline + fi + + read old_args < /etc/kernel/cmdline + local new_args="$(update_args "${old_args}" "${remove_args}" "${add_args}")" + echo "$new_args" > /etc/kernel/cmdline + fi + + 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() { + local prefix="$1" + + [ -z "${prefix}" ] && return + + if [[ -n $remove_kernel && $remove_kernel =~ ^/ ]]; then + remove_kernel="/${remove_kernel##${prefix}/}" + fi + + if [[ -n $initrd ]]; then + initrd="/${initrd##${prefix}/}" + fi + + if [[ -n $extra_initrd ]]; then + extra_initrd=" /${extra_initrd##${prefix}/}" + fi + + if [[ -n $kernel ]]; then + kernel="/${kernel##${prefix}/}" + fi + + if [[ -n $update_kernel && $update_kernel =~ ^/ ]]; then + update_kernel="/${update_kernel##${prefix}/}" + fi +} + +update_grubcfg() +{ + if [[ $arch = 'ppc64' || $arch = 'ppc64le' ]]; then + grub2-mkconfig --no-grubenv-update -o "${grub_config}" >& /dev/null + fi +} + +print_usage() +{ + cat <&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 $update_kernel && -z $kernel ]] && [[ -n $args || -n $remove_args ]]; then + print_error "no action specified" +fi + +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 + +if [[ -z $grub_config ]]; then + grub_config="/boot/grub2/grub.cfg" +fi + +if [[ -z $grub_etc_default ]]; then + grub_etc_default="/etc/default/grub" +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 + +remove_var_prefix "$(get_prefix)" + +if [[ -n $kernel ]]; then + if [[ $copy_default = "true" ]]; then + opts="${bls_options[$default_index]}" + if [[ -n $args ]]; then + opts="${opts} ${args}" + fi + else + opts="${opts} ${args}" + remove_args="$kernelopts" + update_args "${opts}" "${remove_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.8 b/SOURCES/grubby.8 new file mode 100644 index 0000000..9bcd247 --- /dev/null +++ b/SOURCES/grubby.8 @@ -0,0 +1,179 @@ +.TH GRUBBY 8 "Wed Apr 29 2020" +.SH NAME +grubby \- command line tool for configuring grub and zipl + +.SH SYNOPSIS +\fBgrubby\fR [--add-kernel=\fIkernel-path\fR] [--args=\fIargs\fR] + [--bad-image-okay] [--config-file=\fIpath\fR] [--copy-default] + [--default-kernel] [--default-index] [--default-title] + [--env=\fIpath\fR] [--grub2] [--info=\fIkernel-path\fR] + [--initrd=\fIinitrd-path\fR] [--extra-initrd=\fIinitrd-path\fR] + [--make-default] [--remove-args=\fIargs\fR] + [--remove-kernel=\fIkernel-path\fR] [--set-default=\fIkernel-path\fR] + [--set-default-index=\fientry-index\fR] [--title=\fentry-title\fR] + [--update-kernel=\fIkernel-path\fR] [--zipl] [--bls-directory=\fIpath\fR] + +.SH DESCRIPTION +\fBgrubby\fR is a command line tool for updating and displaying information +about the configuration files for the \fBgrub2\fR and \fBzipl\fR 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. + +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 PowerPC platforms, systems +based on Power8 and Power9 support \fBgrub2\fR as a bootloader and use a +configuration stored in \fB/boot/grub2/grub.cfg\fR. On s390x platforms the +\fBzipl\fR bootloader use a default configuration in \fB/etc/zipl.conf\fR. + +All bootloaders define the boot entries as individual configuration fragments +that are stored by default in \fB/boot/loader/entries\fR. The format for the +config files is specified at \fBhttps://systemd.io/BOOT_LOADER_SPECIFICATION\fR. +The \fBgrubby\fR tool is used to update and display the configuration defined +in the BootLoaderSpec fragment files. + +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. +Also, the title of a boot entry may be specified by using \fBTITLE=\fItitle\fR +as the argument; all entries with that title are used. + +.SH OPTIONS +.TP +\fB-\-add-kernel\fR=\fIkernel-path\fR +Add a new boot entry for the kernel located at \fIkernel-path\fR. + +.TP +\fB-\-args\fR=\fIkernel-args\fR +When a new kernel is added, this specifies the command line arguments +which should be passed to the kernel by default (note they are merged +with the arguments of the default entry if \fB-\-copy-default\fR is used). +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. The +\fBroot=\fR kernel argument gets special handling if the configuration +file has special handling for specifying the root filesystem. + +.TP +\fB-\-bad-image-okay\fR +When \fBgrubby\fR is looking for an entry to use for something (such +as 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-\-config-file\fR=\fIpath\fR +Use \fIpath\fR as the configuration file rather then the default. + +.TP +\fB-\-copy-default\fR +\fBgrubby\fR will copy as much information (such as kernel arguments and +root device) as possible from the current default kernel. The kernel path +and initrd path will never be copied. + +.TP +\fB-\-default-kernel\fR +Display the full path to the current default kernel and exit. + +.TP +\fB-\-default-index\fR +Display the numeric index of the current default boot entry and exit. + +.TP +\fB-\-default-title\fR +Display the title of the current default boot entry and exit. + +.TP +\fB-\-env\fR=\fIpath\fR +Use \fIpath\fR as the grub2 environment block file rather then the default path. + +.TP +\fB-\-grub2\fR +Configure \fBgrub2\fR bootloader. + +.TP +\fB-\-info\fR=\fIkernel-path\fR +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-\-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-\-extrainitrd\fR=\fIinitrd-path\fR +Use \fIinitrd-path\fR as the path to an auxiliary init ram disk image to be +added to the boot entry. + +.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 +for the 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. If the +\fBALL\fR argument is used the variable \fB GRUB_CMDLINE_LINUX\fR in +\fB/etc/default/grub\fR is updated with the latest kernel argument list, +unless the \fB-\-no-etc-grub-update\fR option is used. + +.TP +\fB-\-zipl\fR +Configure \fBzipl\fR bootloader. + +.TP +\fB-\-bls-directory\fR=\fIpath\fR +Use \fIpath\fR as the directory for the BootLoaderSpec config files rather +than the default \fB/boot/loader/entries\fR. + +.TP +\fB-\-no-etc-grub-update\fR +Makes grubby to not update the \fBGRUB_CMDLINE_LINUX\fR variable in +\fB/etc/default/grub\fR when the \fB-\-update-kernel\fR option is +used with the \fBALL\fR argument. + +.SH "SEE ALSO" +.BR zipl (8), +.BR mkinitrd (8), +.BR kernel-install (8) + +.SH AUTHORS +.nf +Erik Troan +Jeremy Katz +Peter Jones +Javier Martinez +.fi 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 . +# +# Author(s): tyson@rwii.com +# + +usage() { + echo "Usage: `basename $0` " >&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..878b99d --- /dev/null +++ b/SPECS/grubby.spec @@ -0,0 +1,736 @@ +Name: grubby +Version: 8.40 +Release: 49%{?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 +Source5: grubby.8 +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 +Requires: util-linux + +%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} %{buildroot}%{_sbindir}/grubby +sed -e "s,@@LIBEXECDIR@@,%{_libexecdir}/installkernel,g" %{SOURCE3} \ + > %{buildroot}%{_sbindir}/installkernel +rm %{buildroot}%{_mandir}/man8/grubby.8* +install -m 0644 %{SOURCE5} %{buildroot}%{_mandir}/man8/ + +%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 Jan 10 2024 Marta Lewandowska - 8.40-49 +- Do not overwrite all vars that start with GRUB_CMDLINE_LINUX +- Resolves: #RHEL-12853 + +* Tue Feb 21 2023 Marta Lewandowska - 8.40-48 +- Apply Marta's default args fix +- Resolves: #1900829 + +* Mon Oct 10 2022 Robbie Harwood - 8.40-47 +- Backport fedora/rhel9 initial cmdline population +- Resolves: #2129740 + +* Thu Oct 06 2022 Robbie Harwood - 8.40-46 +- Fix quoting of opts in grubby-bls +- Resolves: #2129740 + +* Thu Aug 11 2022 Robbie Harwood - 8.40-44 +- Write to /etc/kernel/cmdline on non-s390x also +- Resolves: #1978226 + +* Thu Aug 11 2022 Robbie Harwood - 8.40-44 +- Write to /etc/kernel/cmdline on s390x and only s390x +- Resolves: #1978226 + +* Fri Jun 03 2022 Robbie Harwood - 8.40-43 +- Additionally write to /etc/kernel/cmdline +- Resolves: #1978226 + +* Wed Jun 09 2021 Javier Martinez Canillas - 8.40-42 +- grubby-bls: expand only the kernelopts variable + Resolves: rhbz#1819666 + +* Thu May 07 2020 Javier Martinez Canillas - 8.40-41 +- grubby-bls: only attempt to update the cmdline if was already set + Related: rhbz#1152027 + +* Wed May 06 2020 Javier Martinez Canillas - 8.40-40 +- Fix installed man page file mode bits + Related: rhbz#1812065 + +* Wed Apr 29 2020 Javier Martinez Canillas - 8.40-39 +- grubby-bls: strip only /boot from paths + Resolves: rhbz#1738238 +- Make grubby to also update GRUB_CMDLINE_LINUX in /etc/default/grub + Resolves: rhbz#1152027 +- grubby-bls: fix corner case when a kernel param value contains a '=' + Resolves: rhbz#1787584 +- grubby-bls: update man page to match options in current wrapper script + Resolves: rhbz#1812065 +- grubby-bls: always escape the delimiter character used in sed commands + Related: rhbz#1787584 +- grubby-bls: add a --no-etc-grub-update option + Related: rhbz#1152027 + +* Thu Nov 28 2019 Javier Martinez Canillas - 8.40-38 +- grubby-bls: don't print rpm-sort error messages + Resolves: rhbz#1731924 +- grubby-bls: remove -o option and support -c for ppc64le grub config + Resolves: rhbz#1758598 +- grubby-bls: fix logic to check if the kernelopts var is defined in a BLS + Resolves: rhbz#1726514 +- grubby-bls: don't update grubenv when generating grub.cfg for ppc64le + Related: rhbz#1726514 + +* Mon May 20 2019 Javier Martinez Canillas - 8.40-37 +- grubby-bls: unset default entry if is the one being removed + Resolves: rhbz#1668329 +- grubby-bls: error if args or remove-args is used without update-kernel + Related: rhbz#1690765 +- grubby-bls: make --update-kernel ALL to update kernelopts var in grubenv + Resolves: rhbz#1690765 +- grubby-bls: fix --add-kernel not working when using the --args option + Related: rhbz#1690765 + +* Mon May 06 2019 Javier Martinez Canillas - 8.40-36 +- grubby-bls: show absolute path when printing error about incorrect param + Related: rhbz#1706091 + +* Fri May 03 2019 Javier Martinez Canillas - 8.40-35 +- Use mountpoint command to check whether /boot is a mount point + Resolves: rhbz#1706091 + +* Wed Dec 19 2018 Javier Martinez Canillas - 8.40-34 +- grubby-bls: expand all variables in options field when updating it + Resolves: rhbz#1660700 + +* Tue Dec 18 2018 Javier Martinez Canillas - 8.40-33 +- Correctly set LDFLAGS to include hardened flags (pjones) + Related: rhbz#1654936 + +* Tue Dec 04 2018 Javier Martinez Canillas - 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 - 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 - 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 - 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 - 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 - 8.40-27 +- installkernel-bls: remove unnecessary check for GRUB_ENABLE_BLSCFG=true + Resolves: rhbz#1647721 + +* Mon Nov 05 2018 Javier Martinez Canillas - 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 - 8.40-25 +- grubby-bls: fix --default-* options for s390x + Resolves: rhbz#1644608 + +* Fri Oct 26 2018 Javier Martinez Canillas - 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 - 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 - 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 - 8.40-21 +- grubby-bls: escape delimiter character before replacing the options field + Resolves: rhbz#1640017 + +* Tue Oct 16 2018 Peter Jones - 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 - 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 - 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 - 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 - 8.40-16 +- Make grubby-bls execute grub2-mkconfig on ppc64 + Resolves: rhbz#1636039 + +* Fri Sep 28 2018 Peter Jones - 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 - 8.40-14 +- Re-enable debuginfo generation. + Related: rhbz#1619344 + +* Fri Aug 31 2018 Peter Jones - 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 - 8.40-12 +- Use .rpmsave as backup suffix when switching to BLS configuration + +* Fri Apr 06 2018 Javier Martinez Canillas - 8.40-11 +- Switch grub2 config to BLS configuration on %%postun + +* Sat Mar 03 2018 Nathaniel McCallum - 8.40-10 +- Add support for /boot on btrfs subvolumes + +* Wed Feb 07 2018 Fedora Release Engineering - 8.40-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Wed Jan 24 2018 Peter Robinson 8.40-8 +- Drop u-boot uImage generation on ARMv7 +- Minor cleanups + +* Tue Sep 12 2017 Peter Jones - 8.40-7 +- Explicitly require grub2-tools on platforms that need grub2-editenv +- Minor packaging cleanups + +* Wed Aug 02 2017 Fedora Release Engineering - 8.40-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 8.40-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Feb 10 2017 Fedora Release Engineering - 8.40-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Wed Feb 03 2016 Fedora Release Engineering - 8.40-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Jun 17 2015 Fedora Release Engineering - 8.40-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Apr 15 2015 Peter Jones - 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 - 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 - 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 - 8.37-1 +- Update to 8.37 +- Fix test case from 8.35 on ppc64 + Resolves: rhbz#1202876 + +* Thu Nov 13 2014 Peter Jones - 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 - 8.35-8 +- Treat kernel and kernel-core as identical in terms of --make-default + Resolves: rhbz#1141414 + +* Thu Oct 16 2014 Peter Jones - 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 - 8.35-6 +- Update grubby to support device tree options for arm. Again. + Resolves: rhbz#1088933 + +* Fri Sep 26 2014 Peter Jones - 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 - 8.35-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jul 12 2014 Tom Callaway - 8.35-3 +- fix license handling + +* Sat Jun 07 2014 Fedora Release Engineering - 8.35-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 21 2014 Peter Jones - 8.35-1 +- Fix a minor test case error that causes koji builds to fail. + Related: rhbz#1096358 + +* Wed May 21 2014 Peter Jones - 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 - 8.33-1 +- Fix --devtree test in new-kernel-pkg even harder (#1082318) + +* Mon Mar 31 2014 Peter Jones - 8.32-1 +- Fix --devtree test in new-kernel-pkg (#1082318) +- Fix aarch64 #define test. + +* Fri Mar 28 2014 Peter Jones - 8.31-1 +- Update to 8.31 +- Fold in patches from Fedora and RHEL 7 trees + +* Mon Jan 20 2014 Lubomir Rintel - 8.28-2 +- Fix extlinux default + +* Fri Aug 02 2013 Peter Jones - 8.28-1 +- More work on grub's "saved_entry" system. + Resolves: rhbz#768106 + Resolves: rhbz#736188 + +* Tue Jul 30 2013 Peter Jones - 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 - 8.26-2 +- add patch to update extlinux.conf file on arm if it exists + +* Fri May 10 2013 Peter Jones - 8.26-1 +- Conditionally call arm-boot-config's boot.scr generator if available + Resolves: rhbz#952428 + +* Tue Apr 09 2013 Peter Jones - 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 - 8.24-1 +- Fix module remove code from Harald (#923441) + +* Mon Mar 11 2013 Peter Jones - 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 - 8.22-3 +- Add --debug style logging (for both success and failures) to /var/log/grubby + +* Thu Feb 14 2013 Fedora Release Engineering - 8.22-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Fri Jan 04 2013 Peter Jones - 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 - 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 - 8.20-1 +- Handle linuxefi initrd and removal correctly. + Resolves: rhbz#859285 + +* Wed Sep 26 2012 Peter Jones - 8.19-1 +- Don't accidentally migrate from linuxefi back to linux + Related: rhbz#859285 + +* Fri Sep 21 2012 Peter Jones - 8.18-1 +- Change the way the kernel load address is determined for ARM U-Boot. + +* Wed Aug 08 2012 Peter Jones - 8.17-1 +- Update to 8.17 +- Fixes a "make test" failure. + +* Wed Aug 08 2012 Peter Jones - 8.16-1 +- Update to 8.16 +- Handle "linuxefi" directive on grub2/uefi machines. + +* Thu Jul 19 2012 Fedora Release Engineering - 8.15-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jun 25 2012 Peter Jones - 8.15-1 +- Update to 8.15 +- Revert dirname change from 8.13; it was wrong. + +* Thu Jun 14 2012 Peter Jones - 8.14-1 +- Update to 8.14 to fix a build problem. + +* Thu Jun 14 2012 Peter Jones - 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 - 8.12-2 +- Support UBOOT_IMGADDR override on ARM (blc) + +* Thu May 31 2012 Peter Jones - 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 - 8.11-1 +- Update to 8.11 + Resolves: rhbz#805310 + +* Thu Mar 15 2012 Peter Jones - 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 - 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 - 8.8-3 +- add uboot-tools requires on arm arches +- add uboot config file on arm arches + +* Fri Jan 13 2012 Fedora Release Engineering - 8.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 20 2011 Peter Jones - 8.8-1 +- Fix test cases from 8.7 to work on a system without /boot mounted. + +* Tue Dec 20 2011 Peter Jones - 8.7-1 +- Add a --debug to try to help diagnose "No suitable template". (sandeen,pjones) + +* Mon Dec 19 2011 Peter Jones - 8.6-1 +- Fix a "make test" errors introduced in 8.4-1 + +* Sat Dec 17 2011 Peter Jones - 8.5-1 +- Don't hardcode dracut path + Resolves: #768645 + +* Thu Dec 08 2011 Adam Williamson - 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 - 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 - 8.2-1 +- Fixes for xen (from Michael Petullo) + Resolves: rhbz#658387 + +* Fri Jul 22 2011 Peter Jones - 8.1-1 +- Update to 8.1 +- Fix miss-spelled variable name in new-kernel-pkg + +* Thu Jul 21 2011 Peter Jones - 8.0-1 +- Add support for grub2. + +* Tue Jun 07 2011 Brian C. Lane - 7.0.18-1 +- Bump version to 7.0.18 (bcl) +- Fixup new-kernel-pkg errors (#711493) (bcl) + +* Mon Jun 06 2011 Peter Jones - 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 - 7.0.16-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 24 2011 Karsten Hopp 7.0.16-2 +- add BR utils-linux-ng for getopt + +* Tue Jul 13 2010 Brian C. Lane - 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 - 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 - 7.0.14-1 +- Update to 7.0.14 + +* Thu Feb 11 2010 Peter Jones - 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 - 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 - 7.0.11-1 +- Make it possible to update the initrd without any other change. + Related: rhbz#557922 + +* Fri Feb 05 2010 Peter Jones - 7.0.10-1 +- Make --update able to add an initramfs. + Related: rhbz#557922 + +* Mon Nov 30 2009 Peter Jones - 7.0.9-3 +- Use s390utils-base as the s390 dep, not s390utils + Related: rhbz#540565 + +* Tue Nov 24 2009 Peter Jones - 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 - 7.0.9-1 +- Add support for dracut to installkernel (notting) + +* Thu Oct 1 2009 Hans de Goede - 7.0.8-1 +- Stop using nash + +* Fri Sep 11 2009 Hans de Goede - 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 - 7.0.6-1 +- Fix test case breakage from 7.0.5 (rstrode) + +* Fri Sep 11 2009 Peter Jones - 7.0.5-1 +- Add support for plymouth as a second initrd. (rstrode) + Resolves: rhbz#520515 + +* Wed Sep 09 2009 Hans de Goede - 7.0.4-1 +- Add --dracut cmdline argument for %%post generation of dracut initrd + +* Wed Aug 26 2009 Hans de Goede - 7.0.3-1 +- Silence error when no /etc/sysconfig/keyboard (#517187) + +* Fri Aug 7 2009 Hans de Goede - 7.0.2-1 +- Add --add-dracut-args new-kernel-pkg cmdline option + +* Fri Jul 24 2009 Fedora Release Engineering - 7.0.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Fri Jul 17 2009 Jeremy Katz - 7.0.1-1 +- Fix blkid usage (#124246) + +* Wed Jun 24 2009 Jeremy Katz - 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 - 6.0.86-2 +- add instructions for checking out from git + +* Tue Jun 2 2009 Jeremy Katz - 6.0.86-1 +- initial build after splitting out from mkinitrd +