--- trunk/grubby/grubby.c 2014/07/16 10:57:06 2709 +++ trunk/grubby/grubby.c 2016/06/30 10:32:12 2989 @@ -222,6 +222,7 @@ .mbHyperFirst = 1, .mbInitRdIsModule = 1, .mbAllowExtraInitRds = 1, + .titlePosition = 1, }; struct keywordTypes grub2Keywords[] = { @@ -451,6 +452,8 @@ * 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 +467,7 @@ 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); @@ -582,6 +585,8 @@ { "initrd", LT_INITRD, ' ', ',' }, { "append", LT_KERNELARGS, ' ' }, { "prompt", LT_UNKNOWN, ' ' }, + { "fdt", LT_DEVTREE, ' ' }, + { "fdtdir", LT_DEVTREE, ' ' }, { NULL, 0, 0 }, }; int useextlinuxmenu; @@ -592,6 +597,7 @@ .needsBootPrefix = 1, .argsInQuotes = 1, .mbConcatArgs = 1, + .titlePosition = 1, }; struct configFileInfo liloConfigType = { @@ -600,6 +606,7 @@ .entryStart = LT_KERNEL, .argsInQuotes = 1, .maxTitleLength = 15, + .titlePosition = 1, }; struct configFileInfo yabootConfigType = { @@ -610,6 +617,7 @@ .argsInQuotes = 1, .maxTitleLength = 15, .mbAllowExtraInitRds = 1, + .titlePosition = 1, }; struct configFileInfo siloConfigType = { @@ -619,6 +627,7 @@ .needsBootPrefix = 1, .argsInQuotes = 1, .maxTitleLength = 15, + .titlePosition = 1, }; struct configFileInfo ziplConfigType = { @@ -638,6 +647,7 @@ .maxTitleLength = 255, .mbAllowExtraInitRds = 1, .defaultIsUnquoted = 1, + .titlePosition = 1, }; struct grubConfig { @@ -826,13 +836,18 @@ } /* extract the title from within brackets (for zipl) */ -static char * extractTitle(struct singleLine * line) { - /* bracketed title... let's extract it (leaks a byte) */ +static char * extractTitle(struct grubConfig *cfg, struct singleLine * line) { + /* bracketed title... let's extract it */ char * title = NULL; if (line->type == LT_TITLE) { - title = strdup(line->elements[0].item); - title++; - *(title + strlen(title) - 1) = '\0'; + 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 @@ -916,10 +931,23 @@ /* 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; @@ -1255,6 +1283,8 @@ 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); @@ -1271,13 +1301,16 @@ 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 { @@ -1288,6 +1321,7 @@ /* 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); @@ -1298,12 +1332,15 @@ 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. */ @@ -1440,7 +1477,7 @@ line->elements[1].item)) break; } else if (line) { if (!strcmp(defaultLine->elements[1].item, - extractTitle(line))) break; + extractTitle(cfg, line))) break; } i++; entry = NULL; @@ -1491,7 +1528,7 @@ if (!line) line = getLineByType(LT_TITLE, entry->lines); if (line) { - title = extractTitle(line); + title = extractTitle(cfg, line); if (title) cfg->cfi->setEnv(cfg->cfi, "saved_entry", title); } @@ -1529,7 +1566,7 @@ else if (line && (line->numElements == 1) && cfg->cfi->titleBracketed) { fprintf(out, "%sdefault%s%s\n", indent, separator, - extractTitle(line)); + extractTitle(cfg, line)); } } } @@ -1960,11 +1997,13 @@ } indexVars[i + 1] = -1; - + i = 0; if (index) { - while (i < *index) i++; - if (indexVars[i] == -1) return NULL; + while (i < *index) { + i++; + if (indexVars[i] == -1) return NULL; + } } entry = findEntryByIndex(config, indexVars[i]); @@ -2118,8 +2157,12 @@ } else { entry = findEntryByTitle(cfg, defTitle, &index); } - if (entry) + if (entry && suitableImage(entry, prefix, skipRemoved, flags)) { cfg->defaultImage = index; + if (indexPtr) + *indexPtr = index; + return entry; + } } } } else if (cfg->defaultImage > -1) { @@ -2364,9 +2407,11 @@ } else { char * title; line = getLineByType(LT_MENUENTRY, entry->lines); - title = grub2ExtractTitle(line); - if (title) - printf("title=%s\n", title); + if (line) { + title = grub2ExtractTitle(line); + if (title) + printf("title=%s\n", title); + } } for (j = 0, line = entry->lines; line; line = line->next) { @@ -3303,17 +3348,36 @@ } int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel, - const char * image, const char * prefix, const char * initrd) { + 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, newMBKernel, prefix, &index)); index++) { + 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)) @@ -3339,7 +3403,7 @@ } int updateInitrd(struct grubConfig * cfg, const char * image, - const char * prefix, const char * initrd) { + const char * prefix, const char * initrd, const char * title) { struct singleEntry * entry; struct singleLine * line, * kernelLine, *endLine = NULL; int index = 0; @@ -3350,6 +3414,24 @@ 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); @@ -4224,6 +4306,8 @@ _("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, @@ -4364,9 +4448,11 @@ } if (!cfi) { - if (grub2FindConfig(&grub2ConfigType)) + if (grub2FindConfig(&grub2ConfigType)) { cfi = &grub2ConfigType; - else + if (envPath) + cfi->envFile = envPath; + } else #ifdef __ia64__ cfi = &eliloConfigType; #elif __powerpc__ @@ -4408,7 +4494,7 @@ if (newKernelPath && !newKernelTitle) { fprintf(stderr, _("grubby: kernel title must be specified\n")); return 1; - } else if (!newKernelPath && (newKernelTitle || copyDefault || + } else if (!newKernelPath && (copyDefault || (newKernelInitrd && !updateKernelPath)|| makeDefault || extraInitrdCount > 0)) { fprintf(stderr, _("grubby: kernel path expected\n")); @@ -4630,11 +4716,12 @@ if (updateKernelPath && newKernelInitrd) { if (newMBKernel) { if (addMBInitrd(config, newMBKernel, updateKernelPath, - bootPrefix, newKernelInitrd)) + bootPrefix, newKernelInitrd, + newKernelTitle)) return 1; } else { if (updateInitrd(config, updateKernelPath, bootPrefix, - newKernelInitrd)) + newKernelInitrd, newKernelTitle)) return 1; } }