--- trunk/grubby/grubby.c 2014/07/16 10:42:34 2688 +++ trunk/grubby/grubby.c 2016/06/30 10:37:52 2995 @@ -60,7 +60,7 @@ int isEfi = 0; -#if defined(__arch64__) +#if defined(__aarch64__) #define isEfiOnly 1 #else #define isEfiOnly 0 @@ -161,6 +161,7 @@ int defaultIsVariable; int defaultSupportSaved; int defaultIsSaved; + int defaultIsUnquoted; enum lineType_e entryStart; enum lineType_e entryEnd; int needsBootPrefix; @@ -221,6 +222,7 @@ .mbHyperFirst = 1, .mbInitRdIsModule = 1, .mbAllowExtraInitRds = 1, + .titlePosition = 1, }; struct keywordTypes grub2Keywords[] = { @@ -427,7 +429,7 @@ /* 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; @@ -436,10 +438,12 @@ /* 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 */ @@ -450,11 +454,13 @@ * 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; @@ -463,7 +469,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); @@ -581,6 +587,8 @@ { "initrd", LT_INITRD, ' ', ',' }, { "append", LT_KERNELARGS, ' ' }, { "prompt", LT_UNKNOWN, ' ' }, + { "fdt", LT_DEVTREE, ' ' }, + { "fdtdir", LT_DEVTREE, ' ' }, { NULL, 0, 0 }, }; int useextlinuxmenu; @@ -591,6 +599,7 @@ .needsBootPrefix = 1, .argsInQuotes = 1, .mbConcatArgs = 1, + .titlePosition = 1, }; struct configFileInfo liloConfigType = { @@ -599,6 +608,7 @@ .entryStart = LT_KERNEL, .argsInQuotes = 1, .maxTitleLength = 15, + .titlePosition = 1, }; struct configFileInfo yabootConfigType = { @@ -609,6 +619,7 @@ .argsInQuotes = 1, .maxTitleLength = 15, .mbAllowExtraInitRds = 1, + .titlePosition = 1, }; struct configFileInfo siloConfigType = { @@ -618,6 +629,7 @@ .needsBootPrefix = 1, .argsInQuotes = 1, .maxTitleLength = 15, + .titlePosition = 1, }; struct configFileInfo ziplConfigType = { @@ -636,6 +648,8 @@ .needsBootPrefix = 1, .maxTitleLength = 255, .mbAllowExtraInitRds = 1, + .defaultIsUnquoted = 1, + .titlePosition = 1, }; struct grubConfig { @@ -824,13 +838,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 @@ -914,10 +933,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; @@ -1191,16 +1223,13 @@ cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; defaultLine = line; } - } else if (line->type == LT_DEFAULT && line->numElements == 2) { - 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->multiboot) + if (entry && entry->multiboot) line->type = LT_HYPER; } else if (line->type == LT_MBMODULE) { @@ -1226,8 +1255,9 @@ cfg->fallbackImage = strtol(line->elements[1].item, &end, 10); if (*end) cfg->fallbackImage = -1; - } else if (line->type == LT_TITLE && line->numElements > 1) { - /* make the title a single argument (undoing our parsing) */ + } 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); @@ -1255,6 +1285,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 +1303,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 +1323,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 +1334,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. */ @@ -1334,6 +1373,11 @@ } } + 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 @@ -1435,7 +1479,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; @@ -1467,13 +1511,14 @@ 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); @@ -1486,7 +1531,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); } @@ -1497,34 +1542,40 @@ 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(line)); + char *title = extractTitle(cfg, line); + if (title) { + fprintf(out, "%sdefault%s%s\n", indent, separator, title); + free(title); + } } } } @@ -1955,11 +2006,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]); @@ -2113,8 +2166,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) { @@ -2271,6 +2328,7 @@ struct singleLine * line; char * root = NULL; int i; + int j; printf("index=%d\n", index); @@ -2358,9 +2416,25 @@ } 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) { + 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++; + } } } @@ -3283,17 +3357,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)) @@ -3319,7 +3412,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; @@ -3330,6 +3423,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); @@ -4033,6 +4144,13 @@ } } + struct singleLine *endLine = NULL; + endLine = getLineByType(LT_ENTRY_END, new->lines); + if (endLine) { + removeLine(new, endLine); + needs |= NEED_END; + } + /* 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. @@ -4091,6 +4209,7 @@ config->secondaryIndent, NULL); needs &= ~NEED_END; } + if (needs) { printf(_("grubby: needs=%d, aborting\n"), needs); abort(); @@ -4102,21 +4221,6 @@ 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; @@ -4196,6 +4300,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, @@ -4257,8 +4363,6 @@ useextlinuxmenu=0; - signal(SIGSEGV, traceback); - int i = 0; for (int j = 1; j < argc; j++) i += strlen(argv[j]) + 1; @@ -4336,9 +4440,11 @@ } if (!cfi) { - if (grub2FindConfig(&grub2ConfigType)) + if (grub2FindConfig(&grub2ConfigType)) { cfi = &grub2ConfigType; - else + if (envPath) + cfi->envFile = envPath; + } else #ifdef __ia64__ cfi = &eliloConfigType; #elif __powerpc__ @@ -4380,7 +4486,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")); @@ -4552,27 +4658,35 @@ 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); - + 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; + 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); + 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; @@ -4602,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; } }