--- trunk/grubby/grubby.c 2017/06/27 14:37:30 3018 +++ trunk/grubby/grubby.c 2020/07/07 11:09:37 3136 @@ -681,6 +681,8 @@ int fallbackImage; /* just like defaultImage */ int flags; struct configFileInfo *cfi; + int isModified; /* assumes only one entry added + per invocation of grubby */ }; blkid_cache blkid; @@ -1300,6 +1302,7 @@ cfg->theLines = NULL; cfg->entries = NULL; cfg->fallbackImage = 0; + cfg->isModified = 0; /* copy everything we have */ while (*head) { @@ -1709,7 +1712,20 @@ 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); @@ -1776,6 +1792,7 @@ int needs = MAIN_DEFAULT; struct stat sb; int i; + int rc = 0; if (!strcmp(outName, "-")) { out = stdout; @@ -1890,16 +1907,42 @@ } if (tmpOutName) { - if (rename(tmpOutName, outName)) { - fprintf(stderr, - _("grubby: error moving %s to %s: %s\n"), - tmpOutName, outName, strerror(errno)); - unlink(outName); - return 1; + /* 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 flushing data: %m\n")); } - return 0; + return rc; } static int numEntries(struct grubConfig *cfg) @@ -2436,8 +2479,11 @@ 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--; @@ -2498,66 +2544,147 @@ 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; + + /* 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 */ + + /* 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) { + 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 + } else { config->defaultImage = NO_DEFAULT_ENTRY; + } + return; - } else if (defaultKernelPath) { - i = 0; - if (findEntryByPath(config, defaultKernelPath, prefix, &i)) { - config->defaultImage = i; - } else { + } + + /* handle cases where the index value may shift */ + + /* 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)) { + /* don't change default if can't find match */ 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; + config->defaultImage = firstKernelEntryIndex; - if (config->defaultImage >= FIRST_ENTRY_INDEX) - entry = findEntryByIndex(config, config->defaultImage); - else - entry = NULL; + /* this is where we start looking for decrement later */ + currentLookupIndex = config->defaultImage; - if (entry && !entry->skip) { - /* we can preserve the default */ - if (isUserSpecifiedKernelPath) + 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. */ + /* 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)) { + 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--; + } } } @@ -2586,7 +2713,7 @@ } } -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; @@ -2682,7 +2809,14 @@ 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); @@ -3098,11 +3232,11 @@ 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++; } @@ -3432,23 +3566,67 @@ line->numElements--; } -int argMatch(const char *one, const char *two) +static int argNameMatch(const char *one, const char *two) { char *first, *second; - char *chptr; + char *chptra, *chptrb; + int rc; 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 = '\0'; + + chptrb = strchr(second, '='); + if (chptrb) + *chptrb = '\0'; + + rc = strcmp(first, second); + + if (chptra) + *chptra = '='; + if (chptrb) + *chptrb = '='; - chptr = strchr(second, '='); + return rc; +} + +static int argHasValue(const char *arg) +{ + char *chptr; + + chptr = strchr(arg, '='); if (chptr) - *chptr = '\0'; + return 1; + return 0; +} - return strcmp(first, second); +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); + + chptra = strchr(first, '='); + if (chptra) + chptra += 1; + + chptrb = strchr(second, '='); + if (chptrb) + chptrb += 1; + + 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, @@ -3592,7 +3770,7 @@ } if (usedElements[i]) continue; - if (!argMatch(line->elements[i].item, *arg)) { + if (!argNameMatch(line->elements[i].item, *arg)) { usedElements[i] = 1; break; } @@ -3651,9 +3829,12 @@ !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 */ @@ -4729,8 +4910,10 @@ } if (updateImage(config, indexs, prefix, newKernelArgs, NULL, - newMBKernelArgs, NULL)) + newMBKernelArgs, NULL)) { + config->isModified = 1; return 1; + } return 0; } @@ -5263,7 +5446,8 @@ 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))