From ff38bf8209faf54c25e15b1fcec4184fee1f39e9 Mon Sep 17 00:00:00 2001
From: Robert Marshall <rmarshall@redhat.com>
Date: Tue, 13 Dec 2016 18:20:15 -0500
Subject: [PATCH 34/55] Don't assume --make-default just because --set-index
was passed.
grubby previously made the assumption that every time a new
boot entry gets added using --set-index, it should be the default. Due
to this behavior, it also masked an logic error that prevented the
selection of the proper index in cases where it was necessary to
dynamically pick a new default boot entry, or to keep the existing
default boot entry when its position in the config file moved.
Resolves: rhbz#1285601
---
grubby.c | 138 ++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 97 insertions(+), 41 deletions(-)
diff --git a/grubby.c b/grubby.c
index 1f712ec1391..fcca6364887 100644
--- a/grubby.c
+++ b/grubby.c
@@ -2498,66 +2498,121 @@ void markRemovedImage(struct grubConfig *cfg, const char *image,
entry->skip = 1;
}
-void setDefaultImage(struct grubConfig *config, int isUserSpecifiedKernelPath,
+void setDefaultImage(struct grubConfig *config, int isAddingBootEntry,
const char *defaultKernelPath, int newBootEntryIsDefault,
- const char *prefix, int flags, int newDefaultBootEntryIndex)
+ const char *prefix, int flags,
+ int newDefaultBootEntryIndex, int newBootEntryIndex)
{
- struct singleEntry *entry, *entry2, *newDefault;
- int i, j;
+ struct singleEntry *bootEntry, *newDefault;
+ int indexToVerify, firstKernelEntryIndex, currentLookupIndex;
+ /* handle the two cases where the user explictly picks the default
+ * boot entry index as it would exist post-modification */
+
+ /* Case 1: user chose to make the latest boot entry the default */
if (newBootEntryIsDefault) {
- config->defaultImage = FIRST_ENTRY_INDEX;
+ config->defaultImage = newBootEntryIndex;
return;
- } else if ((newDefaultBootEntryIndex >= 0) && config->cfi->defaultIsIndex) {
- if (findEntryByIndex(config, newDefaultBootEntryIndex))
+ }
+
+ /* Case 2: user picked an arbitrary index as the default boot entry */
+ if (newDefaultBootEntryIndex >= FIRST_ENTRY_INDEX
+ && config->cfi->defaultIsIndex) {
+ indexToVerify = newDefaultBootEntryIndex;
+
+ /* user chose to make latest boot entry the default */
+ if (newDefaultBootEntryIndex == newBootEntryIndex) {
+ config->defaultImage = newBootEntryIndex;
+ return;
+ }
+
+ /* the user picks the default index based on the
+ * order of the bootloader configuration after
+ * modification; ensure we are checking for the
+ * existence of the correct entry */
+ if (newBootEntryIndex < newDefaultBootEntryIndex) {
+ if (!config->isModified)
+ indexToVerify--;
+ }
+
+ /* verify the user selected index will exist */
+ if (findEntryByIndex(config, indexToVerify)) {
config->defaultImage = newDefaultBootEntryIndex;
- else
- config->defaultImage = NO_DEFAULT_ENTRY;
- return;
- } else if (defaultKernelPath) {
- i = 0;
- if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
- config->defaultImage = i;
} else {
config->defaultImage = NO_DEFAULT_ENTRY;
- return;
}
- }
- /* defaultImage now points to what we'd like to use, but before any
- * order changes */
- if ((config->defaultImage == DEFAULT_SAVED) ||
- (config->defaultImage == DEFAULT_SAVED_GRUB2))
- /* default is set to saved, we don't want to change it */
return;
+ }
- if (config->defaultImage >= FIRST_ENTRY_INDEX)
- entry = findEntryByIndex(config, config->defaultImage);
- else
- entry = NULL;
+ /* handle cases where the index value may shift */
- if (entry && !entry->skip) {
- /* we can preserve the default */
- if (isUserSpecifiedKernelPath)
+ /* check validity of existing default or first-entry-found
+ selection */
+ if (defaultKernelPath) {
+ /* user requested first-entry-found */
+ if (!findEntryByPath(config, defaultKernelPath,
+ prefix, &firstKernelEntryIndex)) {
+ /* don't change default if can't find match */
+ config->defaultImage = NO_DEFAULT_ENTRY;
+ return;
+ }
+
+ config->defaultImage = firstKernelEntryIndex;
+
+ /* this is where we start looking for decrement later */
+ currentLookupIndex = config->defaultImage;
+
+ if (isAddingBootEntry && !config->isModified &&
+ (newBootEntryIndex < config->defaultImage)) {
+ /* increment because new entry added before default */
config->defaultImage++;
-
- /* count the number of entries erased before this one */
- for (j = 0; j < config->defaultImage; j++) {
- entry2 = findEntryByIndex(config, j);
- if (entry2->skip)
- config->defaultImage--;
}
- } else if (isUserSpecifiedKernelPath) {
- config->defaultImage = FIRST_ENTRY_INDEX;
} else {
- /* Either we just erased the default (or the default line was
- * bad to begin with) and didn't put a new one in. We'll use
- * the first valid image. */
+ /* use pre-existing default entry */
+ currentLookupIndex = config->defaultImage;
+
+ if (isAddingBootEntry
+ && (newBootEntryIndex <= config->defaultImage)) {
+ config->defaultImage++;
+
+ if (config->isModified) {
+ currentLookupIndex++;
+ }
+ }
+ }
+
+ /* sanity check - is this entry index valid? */
+ bootEntry = findEntryByIndex(config, currentLookupIndex);
+
+ if ((bootEntry && bootEntry->skip) || !bootEntry) {
+ /* entry is to be skipped or is invalid */
+ if (isAddingBootEntry) {
+ config->defaultImage = newBootEntryIndex;
+ return;
+ }
newDefault =
findTemplate(config, prefix, &config->defaultImage, 1,
flags);
- if (!newDefault)
+ if (!newDefault) {
config->defaultImage = NO_DEFAULT_ENTRY;
+ }
+
+ return;
+ }
+
+ currentLookupIndex--;
+
+ /* decrement index by the total number of entries deleted */
+
+ for (indexToVerify = currentLookupIndex;
+ indexToVerify >= FIRST_ENTRY_INDEX; indexToVerify--) {
+
+ bootEntry = findEntryByIndex(config, indexToVerify);
+
+ if (bootEntry && bootEntry->skip) {
+ config->defaultImage--;
+ }
}
}
@@ -5265,7 +5320,8 @@ int main(int argc, const char **argv)
markRemovedImage(config, removeKernelPath, bootPrefix);
markRemovedImage(config, removeMBKernel, bootPrefix);
setDefaultImage(config, newKernelPath != NULL, defaultKernel,
- makeDefault, bootPrefix, flags, defaultIndex);
+ makeDefault, bootPrefix, flags, defaultIndex,
+ newIndex);
setFallbackImage(config, newKernelPath != NULL);
if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
removeArgs, newMBKernelArgs, removeMBKernelArgs))
--
2.17.1