This patch adds support for the LT_HYPER line type. Whereas grub uses a kernel=hypervisor module=kernel module=initrd, elilo uses vmm=hypervisor image=kernel initrd=initrd. Adding LT_HYPER support, and extending it backward to grub, makes dealing with this a lot easier. configFileInfo->mbHyperFirst is added to differentiate between grub wanting the hypervisor listed first, and elilo wanting the kernel listed first (image= is the entry separator so it's very important) configFileInfo->mbInitRdIsModule is added to handle grub wanting the initrd listed as a module when multibooting The logic in addNewKernel is considerably rewritten (and cleaned up!) to be more generic and handle elilo alongside grub. Signed-off-by: Aron Griffis <aron@xxxxxx> grubby.c | 463 ++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 285 insertions(+), 178 deletions(-) --- grubby.c.1 2006-06-07 15:31:45.000000000 -0400 +++ grubby.c 2006-06-07 16:14:33.000000000 -0400 @@ -49,9 +49,10 @@ char * indent; }; -enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT, - LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT, - LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC }; +enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_HYPER, + LT_DEFAULT, LT_MBMODULE, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT, + LT_BOOTROOT, LT_LBA, LT_OTHER, LT_GENERIC, LT_UNKNOWN +}; struct singleLine { char * indent; @@ -72,11 +73,12 @@ #define GRUB_CONFIG_NO_DEFAULT (1 << 0) /* don't write out default=0 */ -#define KERNEL_KERNEL (1 << 0) -#define KERNEL_INITRD (1 << 2) -#define KERNEL_TITLE (1 << 3) -#define KERNEL_ARGS (1 << 4) -#define KERNEL_MB (1 << 5) +/* These defines are (only) used in addNewKernel() */ +#define NEED_KERNEL (1 << 0) +#define NEED_INITRD (1 << 2) +#define NEED_TITLE (1 << 3) +#define NEED_ARGS (1 << 4) +#define NEED_MB (1 << 5) #define MAIN_DEFAULT (1 << 0) #define DEFAULT_SAVED -2 @@ -97,6 +99,8 @@ int argsInQuotes; int maxTitleLength; int titleBracketed; + int mbHyperFirst; + int mbInitRdIsModule; }; struct keywordTypes grubKeywords[] = { @@ -107,6 +111,7 @@ { "kernel", LT_KERNEL, ' ' }, { "initrd", LT_INITRD, ' ' }, { "module", LT_MBMODULE, ' ' }, + { "kernel", LT_HYPER, ' ' }, { NULL, 0, 0 }, }; @@ -120,6 +125,8 @@ 0, /* argsInQuotes */ 0, /* maxTitleLength */ 0, /* titleBracketed */ + 1, /* mbHyperFirst */ + 1, /* mbInitRdIsModule */ }; struct keywordTypes yabootKeywords[] = { @@ -173,6 +180,17 @@ { NULL, 0, 0 }, }; +struct keywordTypes eliloKeywords[] = { + { "label", LT_TITLE, '=' }, + { "root", LT_ROOT, '=' }, + { "default", LT_DEFAULT, '=' }, + { "image", LT_KERNEL, '=' }, + { "initrd", LT_INITRD, '=' }, + { "append", LT_KERNELARGS, '=' }, + { "vmm", LT_HYPER, '=' }, + { NULL, 0, 0 }, +}; + struct keywordTypes siloKeywords[] = { { "label", LT_TITLE, '=' }, { "root", LT_ROOT, '=' }, @@ -196,7 +214,7 @@ struct configFileInfo eliloConfigType = { "/boot/efi/EFI/redhat/elilo.conf", /* defaultConfig */ - liloKeywords, /* keywords */ + eliloKeywords, /* keywords */ 0, /* defaultIsIndex */ 0, /* defaultSupportSaved */ LT_KERNEL, /* entrySeparator */ @@ -204,6 +222,8 @@ 1, /* argsInQuotes */ 0, /* maxTitleLength */ 0, /* titleBracketed */ + 0, /* mbHyperFirst */ + 0, /* mbInitRdIsModule */ }; struct configFileInfo liloConfigType = { @@ -216,6 +236,8 @@ 1, /* argsInQuotes */ 15, /* maxTitleLength */ 0, /* titleBracketed */ + 0, /* mbHyperFirst */ + 0, /* mbInitRdIsModule */ }; struct configFileInfo yabootConfigType = { @@ -228,6 +250,8 @@ 1, /* argsInQuotes */ 15, /* maxTitleLength */ 0, /* titleBracketed */ + 0, /* mbHyperFirst */ + 0, /* mbInitRdIsModule */ }; struct configFileInfo siloConfigType = { @@ -240,6 +264,8 @@ 1, /* argsInQuotes */ 15, /* maxTitleLength */ 0, /* titleBracketed */ + 0, /* mbHyperFirst */ + 0, /* mbInitRdIsModule */ }; struct configFileInfo ziplConfigType = { @@ -252,6 +278,8 @@ 1, /* argsInQuotes */ 15, /* maxTitleLength */ 1, /* titleBracketed */ + 0, /* mbHyperFirst */ + 0, /* mbInitRdIsModule */ }; struct grubConfig { @@ -656,11 +684,46 @@ if (line->type == LT_DEFAULT && line->numElements == 2) { cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT; defaultLine = line; + + } else if (line->type == LT_KERNEL) { + /* 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) { + struct singleLine * l; + for (l = entry->lines; l; l = l->next) { + if (l->type == LT_MBMODULE) { + line->type = LT_HYPER; /* caught it! */ + break; + } + } + } + } else if (line->type == LT_MBMODULE) { + /* go back and fix the LT_KERNEL line to indicate LT_HYPER + * instead, now that we know this is a multiboot entry. + * This only applies to grub, but that's the only place we + * should find LT_MBMODULE lines anyway. + */ + struct singleLine * l; + for (l = entry->lines; l; l = l->next) { + if (l->type == LT_HYPER) + break; + else if (l->type == LT_KERNEL) { + l->type = LT_HYPER; + break; + } + } entry->multiboot = 1; + + } else if (line->type == LT_HYPER) { + entry->multiboot = 1; + } else if (line->type == LT_FALLBACK && line->numElements == 2) { 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) */ len = 0; @@ -685,6 +748,7 @@ line->elements[line->numElements - 1].indent; line->elements[1].item = buf; line->numElements = 2; + } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) { /* Strip off any " which may be present; they'll be put back on write. This is one of the few (the only?) places that grubby @@ -702,7 +766,6 @@ if (line->elements[last].item[len] == '"') line->elements[last].item[len] = '\0'; } - } /* If we find a generic config option which should live at the @@ -964,7 +1027,7 @@ if (skipRemoved && entry->skip) return 0; - line = getLineByType(LT_KERNEL, entry->lines); + line = getLineByType2(LT_KERNEL, LT_HYPER, entry->lines); if (!line || line->numElements < 2) return 0; if (flags & GRUBBY_BADIMAGE_OKAY) return 1; @@ -1061,7 +1124,7 @@ entry = findEntryByIndex(config, indexVars[i]); if (!entry) return NULL; - line = getLineByType(LT_KERNEL, entry->lines); + line = getLineByType2(LT_KERNEL, LT_HYPER, entry->lines); if (!line) return NULL; if (index) *index = indexVars[i]; @@ -1104,7 +1167,10 @@ } for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) { - line = getLineByType(checkType, entry->lines); + if (checkType == LT_KERNEL) + line = getLineByType2(LT_KERNEL, LT_HYPER, entry->lines); + else + line = getLineByType(checkType, entry->lines); if (line && line->numElements >= 2 && !entry->skip) { rootspec = getRootSpecifier(line->elements[1].item); @@ -1134,7 +1200,7 @@ /* make sure this entry has a kernel identifier; this skips non-Linux boot entries (could find netbsd etc, though, which is unfortunate) */ - line = getLineByType(LT_KERNEL, entry->lines); + line = getLineByType2(LT_KERNEL, LT_HYPER, entry->lines); if (!line) { if (!index) index = &i; (*index)++; @@ -1307,7 +1373,7 @@ printf("index=%d\n", index); - line = getLineByType(LT_KERNEL, entry->lines); + line = getLineByType2(LT_KERNEL, LT_HYPER, entry->lines); printf("kernel=%s\n", line->elements[1].item); if (line->numElements >= 3) { @@ -1496,7 +1562,8 @@ insertElement(newLine, val, 1); /* but try to keep the rootspec from the template... sigh */ - if (tmplLine->type == LT_KERNEL || + if (tmplLine->type == LT_HYPER || + tmplLine->type == LT_KERNEL || tmplLine->type == LT_MBMODULE || tmplLine->type == LT_INITRD) { @@ -2112,13 +2179,9 @@ char * newKernelArgs, char * newKernelInitrd, char * newMBKernel, char * newMBKernelArgs) { struct singleEntry * new; - struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL; + struct singleLine * newLine = NULL, * tmplLine = NULL; int needs; - char * indent = NULL; - char * rootspec = NULL; char * chptr; - int i; - enum lineType_e type; if (!newKernelPath) return 0; @@ -2148,66 +2211,113 @@ config->entries = new; /* copy/update from the template */ - needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE; + needs = NEED_KERNEL | NEED_TITLE; + if (newKernelInitrd) + needs |= NEED_INITRD; if (newMBKernel) { - needs |= KERNEL_MB; + needs |= NEED_MB; new->multiboot = 1; } if (template) { for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) { - /* remember the indention level; we may need it for new lines */ - if (tmplLine->numElements) - indent = tmplLine->indent; - /* skip comments */ chptr = tmplLine->indent; while (*chptr && isspace(*chptr)) chptr++; if (*chptr == '#') continue; - /* we don't need an initrd here */ - if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue; - - if (tmplLine->type == LT_KERNEL && - !template->multiboot && (needs & KERNEL_MB)) { - struct singleLine *l; - needs &= ~ KERNEL_MB; - - l = addLine(new, config->cfi, LT_KERNEL, - config->secondaryIndent, - newMBKernel + strlen(prefix)); - - tmplLine = lastLine; - if (!new->lines) { - new->lines = l; - } else { - newLine->next = l; - newLine = l; - } - continue; - } else if (tmplLine->type == LT_KERNEL && - template->multiboot && !new->multiboot) { - continue; /* don't need multiboot kernel here */ - } + if (tmplLine->type == LT_KERNEL && + tmplLine->numElements >= 2) { + if (!template->multiboot && (needs & NEED_MB)) { + /* it's not a multiboot template and this is the kernel + * line. Try to be intelligent about inserting the + * hypervisor at the same time. + */ + if (config->cfi->mbHyperFirst) { + /* insert the hypervisor first */ + newLine = addLine(new, config->cfi, LT_HYPER, + tmplLine->indent, + newMBKernel + strlen(prefix)); + /* set up for adding the kernel line */ + free(tmplLine->indent); + tmplLine->indent = strdup(config->secondaryIndent); + needs &= ~NEED_MB; + } + if (needs & NEED_KERNEL) { + /* use addLineTmpl to preserve line elements, + * otherwise we could just call addLine. Unfortunately + * this means making some changes to the template + * such as the indent change above and the type + * change below. + */ + struct keywordTypes * mbm_kw = + getKeywordByType(LT_MBMODULE, config->cfi); + if (mbm_kw) { + tmplLine->type = LT_MBMODULE; + free(tmplLine->elements[0].item); + tmplLine->elements[0].item = strdup(mbm_kw->key); + } + newLine = addLineTmpl(new, tmplLine, newLine, + newKernelPath + strlen(prefix)); + needs &= ~NEED_KERNEL; + } + if (needs & NEED_MB) { /* !mbHyperFirst */ + newLine = addLine(new, config->cfi, LT_HYPER, + config->secondaryIndent, + newMBKernel + strlen(prefix)); + needs &= ~NEED_MB; + } + } else if (needs & NEED_KERNEL) { + newLine = addLineTmpl(new, tmplLine, newLine, + newKernelPath + strlen(prefix)); + needs &= ~NEED_KERNEL; + } - if (!new->lines) { - newLine = malloc(sizeof(*newLine)); - new->lines = newLine; - } else { - newLine->next = malloc(sizeof(*newLine)); - newLine = newLine->next; - } + } else if (tmplLine->type == LT_HYPER && + tmplLine->numElements >= 2) { + if (new->multiboot) { + if (needs & NEED_MB) { + newLine = addLineTmpl(new, tmplLine, newLine, + newMBKernel + strlen(prefix)); + needs &= ~NEED_MB; + } + } else if (needs & NEED_KERNEL) { + /* template is multi but new is not, + * insert the kernel where the hypervisor was before + */ + tmplLine->type = LT_KERNEL; + free(tmplLine->elements[0].item); + tmplLine->elements[0].item = + strdup(getKeywordByType(LT_KERNEL, config->cfi)->key); + newLine = addLineTmpl(new, tmplLine, newLine, + newKernelPath + strlen(prefix)); + needs &= ~NEED_KERNEL; + } + } else if (tmplLine->type == LT_MBMODULE && + tmplLine->numElements >= 2) { + if (new->multiboot) { + if (needs & NEED_KERNEL) { + newLine = addLineTmpl(new, tmplLine, newLine, + newKernelPath + + strlen(prefix)); + needs &= ~NEED_KERNEL; + } else if (config->cfi->mbInitRdIsModule && + (needs & NEED_INITRD)) { + newLine = addLineTmpl(new, tmplLine, newLine, + newKernelInitrd); + needs &= ~NEED_INITRD; + } + } else if (needs & NEED_INITRD) { + /* template is multi but new is not, + * insert the initrd where the module was before + */ + newLine = addLine(new, config->cfi, LT_INITRD, + config->secondaryIndent, + newKernelInitrd + strlen(prefix)); + needs &= ~NEED_INITRD; + } - newLine->indent = strdup(tmplLine->indent); - newLine->next = NULL; - newLine->type = tmplLine->type; - newLine->numElements = tmplLine->numElements; - newLine->elements = malloc(sizeof(*newLine->elements) * - newLine->numElements); - for (i = 0; i < newLine->numElements; i++) { - newLine->elements[i].item = strdup(tmplLine->elements[i].item); - newLine->elements[i].indent = strdup(tmplLine->elements[i].indent); } @@ -2257,127 +2367,124 @@ strlen(prefix)); } } else if (tmplLine->type == LT_INITRD && - tmplLine->numElements >= 2) { - needs &= ~KERNEL_INITRD; - free(newLine->elements[1].item); - if (new->multiboot && !template->multiboot) { - free(newLine->elements[0].item); - newLine->elements[0].item = strdup("module"); - newLine->type = LT_MBMODULE; - } - rootspec = getRootSpecifier(tmplLine->elements[1].item); - if (rootspec != NULL) { - newLine->elements[1].item = sdupprintf("%s%s", - rootspec, - newKernelInitrd + - strlen(prefix)); - } else { - newLine->elements[1].item = strdup(newKernelInitrd + - strlen(prefix)); - } - } else if (tmplLine->type == LT_MBMODULE && - tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) { - needs &= ~KERNEL_INITRD; - if (!new->multiboot && template->multiboot) { - free(newLine->elements[0].item); - newLine->elements[0].item = strdup("initrd"); - newLine->type = LT_INITRD; - } - free(newLine->elements[1].item); - rootspec = getRootSpecifier(tmplLine->elements[1].item); - if (rootspec != NULL) { - newLine->elements[1].item = sdupprintf("%s%s", - rootspec, - newKernelInitrd + - strlen(prefix)); - } else { - newLine->elements[1].item = strdup(newKernelInitrd + - strlen(prefix)); - } - } else if (tmplLine->type == LT_TITLE && - tmplLine->numElements >= 2) { - needs &= ~KERNEL_TITLE; - - for (i = 1; i < newLine->numElements; i++) { - free(newLine->elements[i].item); - free(newLine->elements[i].indent); + tmplLine->numElements >= 2 && + (needs & NEED_INITRD)) { + if (new->multiboot && !template->multiboot && + config->cfi->mbInitRdIsModule) { + /* make sure we don't insert the module initrd + * before the module kernel... if we don't do it here, + * it will be inserted following the template. + */ + if (!needs & NEED_KERNEL) { + newLine = addLine(new, config->cfi, LT_MBMODULE, + config->secondaryIndent, + newKernelInitrd + strlen(prefix)); + needs &= ~NEED_INITRD; + } + } else { + newLine = addLineTmpl(new, tmplLine, newLine, + newKernelInitrd + strlen(prefix)); + needs &= ~NEED_INITRD; } - newLine->elements[1].item = strdup(newKernelTitle); - newLine->elements[1].indent = strdup(""); - newLine->numElements = 2; } else if (tmplLine->type == LT_TITLE && - config->cfi->titleBracketed && - tmplLine->numElements == 1) { - needs &= ~KERNEL_TITLE; - free(newLine->elements[0].item); - free(newLine->elements[0].indent); - newLine->elements = malloc(sizeof(*newLine->elements) * - newLine->numElements); - - newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3); - sprintf(newLine->elements[0].item, "[%s]", newKernelTitle); - newLine->elements[0].indent = strdup(""); - newLine->numElements = 1; - } + (needs & NEED_TITLE)) { + if (tmplLine->numElements >= 2) { + newLine = addLineTmpl(new, tmplLine, newLine, + newKernelTitle); + needs &= ~NEED_TITLE; + } else if (tmplLine->numElements == 1 && + config->cfi->titleBracketed) { + /* addLineTmpl doesn't handle titleBracketed */ + newLine = addLine(new, config->cfi, LT_TITLE, + tmplLine->indent, newKernelTitle); + needs &= ~NEED_TITLE; + } + + } else { + /* pass through other lines from the template */ + newLine = addLineTmpl(new, tmplLine, newLine, NULL); + } } + } else { - for (i = 0; config->cfi->keywords[i].key; i++) { - if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER)) + /* don't have a template, so start the entry with the + * appropriate starting line + */ + switch (config->cfi->entrySeparator) { + case LT_KERNEL: + if (new->multiboot && config->cfi->mbHyperFirst) { + /* fall through to LT_HYPER */ + } else { + newLine = addLine(new, config->cfi, LT_KERNEL, + config->primaryIndent, + newKernelPath + strlen(prefix)); + needs &= ~NEED_KERNEL; + break; + } + + case LT_HYPER: + newLine = addLine(new, config->cfi, LT_HYPER, + config->primaryIndent, + newMBKernel + strlen(prefix)); + needs &= ~NEED_MB; break; - } - switch (config->cfi->keywords[i].type) { - case LT_KERNEL: needs &= ~KERNEL_KERNEL, - chptr = newKernelPath + strlen(prefix); - type = LT_KERNEL; break; - case LT_TITLE: needs &= ~KERNEL_TITLE, chptr = newKernelTitle; - type = LT_TITLE; break; - default: - /* zipl strikes again */ - if (config->cfi->titleBracketed) { - needs &= ~KERNEL_TITLE; - chptr = newKernelTitle; - type = LT_TITLE; - break; - } else { - abort(); - } - } + case LT_TITLE: + newLine = addLine(new, config->cfi, LT_TITLE, + config->primaryIndent, newKernelTitle); + needs &= ~NEED_TITLE; + break; - newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr); - new->lines = newLine; + default: + abort(); + } } - if (new->multiboot) { - if (needs & KERNEL_MB) - newLine = addLine(new, config->cfi, LT_KERNEL, - config->secondaryIndent, - newMBKernel + strlen(prefix)); - if (needs & KERNEL_KERNEL) - newLine = addLine(new, config->cfi, LT_MBMODULE, - config->secondaryIndent, - newKernelPath + strlen(prefix)); - /* don't need to check for title as it's guaranteed to have been - * done as we only do multiboot with grub which uses title as - * a separator */ - if (needs & KERNEL_INITRD && newKernelInitrd) - newLine = addLine(new, config->cfi, LT_MBMODULE, - config->secondaryIndent, - newKernelInitrd + strlen(prefix)); - } else { - if (needs & KERNEL_KERNEL) - newLine = addLine(new, config->cfi, LT_KERNEL, - config->secondaryIndent, - newKernelPath + strlen(prefix)); - if (needs & KERNEL_TITLE) - newLine = addLine(new, config->cfi, LT_TITLE, - config->secondaryIndent, - newKernelTitle); - if (needs & KERNEL_INITRD && newKernelInitrd) - newLine = addLine(new, config->cfi, LT_INITRD, - config->secondaryIndent, - newKernelInitrd + strlen(prefix)); + /* 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 entrySeparator. + */ + if (needs & NEED_TITLE) { + newLine = addLine(new, config->cfi, LT_TITLE, + config->secondaryIndent, + newKernelTitle); + needs &= ~NEED_TITLE; + } + if ((needs & NEED_MB) && config->cfi->mbHyperFirst) { + newLine = addLine(new, config->cfi, LT_HYPER, + config->secondaryIndent, + newMBKernel + strlen(prefix)); + needs &= ~NEED_MB; + } + if (needs & NEED_KERNEL) { + newLine = addLine(new, config->cfi, + (new->multiboot && getKeywordByType(LT_MBMODULE, + config->cfi)) ? + LT_MBMODULE : LT_KERNEL, + config->secondaryIndent, + newKernelPath + strlen(prefix)); + needs &= ~NEED_KERNEL; + } + if (needs & NEED_MB) { + newLine = addLine(new, config->cfi, LT_HYPER, + config->secondaryIndent, + newMBKernel + strlen(prefix)); + needs &= ~NEED_MB; + } + if (needs & NEED_INITRD) { + newLine = addLine(new, config->cfi, + (new->multiboot && getKeywordByType(LT_MBMODULE, + config->cfi)) ? + LT_MBMODULE : LT_INITRD, + config->secondaryIndent, + newKernelInitrd + strlen(prefix)); + needs &= ~NEED_INITRD; + } + + if (needs) { + printf(_("grubby: needs=%d, aborting\n"), needs); + abort(); } if (updateImage(config, "0", prefix, newKernelArgs, NULL,