--- trunk/grubby/grubby.c 2013/10/21 14:01:48 2257 +++ trunk/grubby/grubby.c 2016/06/30 10:37:52 2995 @@ -60,6 +60,12 @@ int isEfi = 0; +#if defined(__aarch64__) +#define isEfiOnly 1 +#else +#define isEfiOnly 0 +#endif + char *saved_command_line = NULL; /* comments get lumped in with indention */ @@ -90,7 +96,10 @@ LT_SET_VARIABLE = 1 << 19, LT_KERNEL_EFI = 1 << 20, LT_INITRD_EFI = 1 << 21, - LT_UNKNOWN = 1 << 22, + LT_KERNEL_16 = 1 << 22, + LT_INITRD_16 = 1 << 23, + LT_DEVTREE = 1 << 24, + LT_UNKNOWN = 1 << 25, }; struct singleLine { @@ -119,6 +128,7 @@ #define NEED_ARGS (1 << 3) #define NEED_MB (1 << 4) #define NEED_END (1 << 5) +#define NEED_DEVTREE (1 << 6) #define MAIN_DEFAULT (1 << 0) #define DEFAULT_SAVED -2 @@ -151,6 +161,7 @@ int defaultIsVariable; int defaultSupportSaved; int defaultIsSaved; + int defaultIsUnquoted; enum lineType_e entryStart; enum lineType_e entryEnd; int needsBootPrefix; @@ -182,6 +193,8 @@ "/boot/grub/grub.conf", "/boot/grub/menu.lst", "/etc/grub.conf", + "/boot/grub2/grub.cfg", + "/boot/grub2-efi/grub.cfg", NULL }; static int i = -1; @@ -209,6 +222,7 @@ .mbHyperFirst = 1, .mbInitRdIsModule = 1, .mbAllowExtraInitRds = 1, + .titlePosition = 1, }; struct keywordTypes grub2Keywords[] = { @@ -221,10 +235,13 @@ { "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 }, }; @@ -273,8 +290,8 @@ 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); + char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv"; + int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name); if (rc < 0) return NULL; @@ -338,14 +355,14 @@ { char *s = NULL; int rc = 0; - char *envFile = info->envFile ? info->envFile : "/boot/grub2/grubenv"; + char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv"; unquote(value); value = shellEscape(value); if (!value) return -1; - rc = asprintf(&s, "grub2-editenv %s set '%s=%s'", envFile, name, value); + rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value); free(value); if (rc <0) return -1; @@ -396,11 +413,11 @@ } static int iskernel(enum lineType_e type) { - return (type == LT_KERNEL || type == LT_KERNEL_EFI); + 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); + return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16); } char *grub2ExtractTitle(struct singleLine * line) { @@ -412,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; @@ -421,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 */ @@ -435,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; @@ -448,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); @@ -566,6 +587,8 @@ { "initrd", LT_INITRD, ' ', ',' }, { "append", LT_KERNELARGS, ' ' }, { "prompt", LT_UNKNOWN, ' ' }, + { "fdt", LT_DEVTREE, ' ' }, + { "fdtdir", LT_DEVTREE, ' ' }, { NULL, 0, 0 }, }; int useextlinuxmenu; @@ -576,6 +599,7 @@ .needsBootPrefix = 1, .argsInQuotes = 1, .mbConcatArgs = 1, + .titlePosition = 1, }; struct configFileInfo liloConfigType = { @@ -584,6 +608,7 @@ .entryStart = LT_KERNEL, .argsInQuotes = 1, .maxTitleLength = 15, + .titlePosition = 1, }; struct configFileInfo yabootConfigType = { @@ -594,6 +619,7 @@ .argsInQuotes = 1, .maxTitleLength = 15, .mbAllowExtraInitRds = 1, + .titlePosition = 1, }; struct configFileInfo siloConfigType = { @@ -603,6 +629,7 @@ .needsBootPrefix = 1, .argsInQuotes = 1, .maxTitleLength = 15, + .titlePosition = 1, }; struct configFileInfo ziplConfigType = { @@ -621,6 +648,8 @@ .needsBootPrefix = 1, .maxTitleLength = 255, .mbAllowExtraInitRds = 1, + .defaultIsUnquoted = 1, + .titlePosition = 1, }; struct grubConfig { @@ -712,12 +741,23 @@ if (isEfi && cfi == &grub2ConfigType) { switch (type) { case LT_KERNEL: - return LT_KERNEL_EFI; + 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_EFI; + return LT_INITRD_16; default: return type; } +#endif } return type; } @@ -798,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 @@ -888,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; @@ -1066,6 +1124,15 @@ 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; +} + static struct grubConfig * readConfig(const char * inName, struct configFileInfo * cfi) { int in; @@ -1156,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) { @@ -1191,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); @@ -1220,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); @@ -1236,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 { @@ -1253,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); @@ -1263,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. */ @@ -1299,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 @@ -1362,7 +1441,12 @@ char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); if (defTitle) { int index = 0; - entry = findEntryByTitle(cfg, defTitle, &index); + if (isnumber(defTitle)) { + index = atoi(defTitle); + entry = findEntryByIndex(cfg, index); + } else { + entry = findEntryByTitle(cfg, defTitle, &index); + } if (entry) cfg->defaultImage = index; } @@ -1395,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; @@ -1411,7 +1495,12 @@ char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry"); if (defTitle) { int index = 0; - entry = findEntryByTitle(cfg, defTitle, &index); + if (isnumber(defTitle)) { + index = atoi(defTitle); + entry = findEntryByIndex(cfg, index); + } else { + entry = findEntryByTitle(cfg, defTitle, &index); + } if (entry) cfg->defaultImage = index; } @@ -1422,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); @@ -1441,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); } @@ -1452,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); + } } } } @@ -1786,7 +1882,7 @@ return 0; } - line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines); + 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; @@ -1910,17 +2006,19 @@ } 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]); if (!entry) return NULL; - line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines); + line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); if (!line) return NULL; if (index) *index = indexVars[i]; @@ -1971,9 +2069,9 @@ 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; + ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16; else if (checkType & LT_KERNEL) - ct = checkType | LT_KERNEL_EFI; + ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16; line = getLineByType(ct, line); if (!line) break; /* not found in this entry */ @@ -1995,7 +2093,7 @@ * non-Linux boot entries (could find netbsd etc, though, which is * unfortunate) */ - if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines)) + if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines)) break; /* found 'im! */ } @@ -2062,7 +2160,18 @@ char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry"); if (defTitle) { int index = 0; - entry = findEntryByTitle(cfg, defTitle, &index); + 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) { @@ -2219,10 +2328,11 @@ struct singleLine * line; char * root = NULL; int i; + int j; printf("index=%d\n", index); - line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines); + line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); if (!line) { printf("non linux entry\n"); return; @@ -2287,7 +2397,7 @@ printf("root=%s\n", s); } - line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines); + 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))) @@ -2306,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++; + } } } @@ -2704,7 +2830,7 @@ 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)) { + 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); @@ -3074,7 +3200,7 @@ firstElement = 2; } else { - line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines); + 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; @@ -3230,8 +3356,63 @@ 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; + } + + return 0; +} + 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; @@ -3239,10 +3420,28 @@ if (!image) return 0; for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { - kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines); + kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); if (!kernelLine) continue; - line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines); + /* 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) { @@ -3253,8 +3452,21 @@ endLine = getLineByType(LT_ENTRY_END, entry->lines); if (endLine) removeLine(entry, endLine); - line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi), - kernelLine->indent, initrd); + 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) { @@ -3613,7 +3825,8 @@ 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 * newMBKernel, const char * newMBKernelArgs, + const char * newDevTreePath) { struct singleEntry * new; struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL; int needs; @@ -3654,6 +3867,8 @@ needs |= NEED_MB; new->multiboot = 1; } + if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi)) + needs |= NEED_DEVTREE; if (template) { for (masterLine = template->lines; @@ -3839,6 +4054,21 @@ 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); @@ -3852,6 +4082,7 @@ 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 { @@ -3913,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. @@ -3958,6 +4196,14 @@ 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); @@ -3975,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; @@ -4009,7 +4240,7 @@ char * newKernelArgs = NULL; char * newKernelInitrd = NULL; char * newKernelTitle = NULL; - char * newKernelVersion = NULL; + char * newDevTreePath = NULL; char * newMBKernel = NULL; char * newMBKernelArgs = NULL; char * removeMBKernelArgs = NULL; @@ -4067,6 +4298,10 @@ _("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, @@ -4128,8 +4363,6 @@ useextlinuxmenu=0; - signal(SIGSEGV, traceback); - int i = 0; for (int j = 1; j < argc; j++) i += strlen(argv[j]) + 1; @@ -4207,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__ @@ -4232,7 +4467,7 @@ grubConfig = cfi->defaultConfig; } - if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion || + if (bootloaderProbe && (displayDefault || kernelInfo || newKernelPath || removeKernelPath || makeDefault || defaultKernel || displayDefaultIndex || displayDefaultTitle || (defaultIndex >= 0))) { @@ -4241,7 +4476,7 @@ return 1; } - if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath || + if ((displayDefault || kernelInfo) && (newKernelPath || removeKernelPath)) { fprintf(stderr, _("grubby: --default-kernel and --info may not " "be used when adding or removing kernels\n")); @@ -4251,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")); @@ -4410,7 +4645,7 @@ if (!entry) return 0; if (!suitableImage(entry, bootPrefix, 0, flags)) return 0; - line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines); + line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); if (!line) return 0; rootspec = getRootSpecifier(line->elements[1].item); @@ -4423,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; @@ -4471,13 +4714,21 @@ if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs, removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1; if (updateKernelPath && newKernelInitrd) { - if (updateInitrd(config, updateKernelPath, bootPrefix, - newKernelInitrd)) return 1; + 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)) return 1; + newMBKernel, newMBKernelArgs, newDevTreePath)) return 1; if (numEntries(config) == 0) {