This patch adds getSubvolPrefix() for handling a btrfs subvol prefix on the filenames for grub2. If get_Root_Specifier() results in a NULL rootspec, then getSubvolPrefix() is executed to extract any btrfs subvol prefix. With this modification, booting off /boot on a btrfs subvol is supported. To determine if booting is to be performed off a btrfs volume or subvolume, the lines of the entry are scanned to detect if "insmod btrfs" is present. If it is, then btrfs is assumed. If the kernel filename includes only one slash, then there is no btrfs prefix. Otherwise, the first part defined by "/../" will be the btrfs prefix if booting btrfs. Unless, of course, there are 2 slashes in the filename but bootPrefix is zero length in which case we are booting off a btrfs volume! Besides the kernel, the subvol prefix must also be on the initrd filename. The subvol prefix for initrd is based on the entry's kernel's filename. Note that the lines of the entry must be scanned to determine if we are booting on btrfs. Code was added to addLine(tmpl() so that the subvol prefix not added for an initrd since updateInitrd() does that already. --- grubby.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 124 insertions(+), 8 deletions(-) diff --git a/grubby.c b/grubby.c index e47e97b..773f55e 100644 --- a/grubby.c +++ b/grubby.c @@ -690,6 +690,8 @@ static int lineWrite(FILE * out, struct singleLine * line, static int getNextLine(char ** bufPtr, struct singleLine * line, struct configFileInfo * cfi); static char * getRootSpecifier(char * str); +static char * getSubvolPrefix(struct singleLine * line, char * str); +static char * findBootPrefix(void); static void requote(struct singleLine *line, struct configFileInfo * cfi); static void insertElement(struct singleLine * line, const char * item, int insertHere, @@ -1843,6 +1845,57 @@ static int endswith(const char *s, char c) return s[slen] == c; } + +/* extract any btrfs prefix on filename */ +/* the passed string is elements[1] */ +static char * getSubvolPrefix(struct singleLine * line, char * str) { + char *idx, *svPrefix = NULL; + int slashcnt = 0; + const char * bootPrefix = findBootPrefix(); + static int btrfsBootFlag = 0; + + if (btrfsBootFlag == 0){ + for (; line; line = line->next) { + dbgPrintf("checkForBtrfsBoot(%s)\n", + line->numElements >0 ? line->elements[0].item : ""); + if (line->numElements >1) { + if ((strcasecmp(line->elements[0].item,"insmod")==0) && + (strcasecmp(line->elements[1].item,"btrfs")==0)) { + dbgPrintf("NOTE: booting from a btrfs volume or subvolume\n"); + btrfsBootFlag = -1; + break; + } + } + } + } + + idx = str; + while (*idx) { + if (*idx == '/') + slashcnt++; + idx++; + } + + if ((btrfsBootFlag == 0) || + (slashcnt == 0) || + (slashcnt == 1)) + svPrefix = NULL; + + else if ((slashcnt == 2) && (strlen(bootPrefix) == 0)) + svPrefix = NULL; + + else if ((btrfsBootFlag == -1) && (*str == '/')) { + idx = svPrefix = strdup(str); + idx++; + while(*idx && (*idx != '/') && (!isspace(*idx))) idx++; + *idx = '\0'; /* strip off the second slash */ + } + dbgPrintf("getSubvolPrefix(): btrfsBootFlag=%i, slashcnt=%i, str='%s', bootPrefix='%s', svPrefix='%s'\n", + btrfsBootFlag, slashcnt, str, bootPrefix, svPrefix); + + return svPrefix; +} + int suitableImage(struct singleEntry * entry, const char * bootPrefix, int skipRemoved, int flags) { struct singleLine * line; @@ -1873,14 +1926,21 @@ int suitableImage(struct singleEntry * entry, const char * bootPrefix, return 1; } + dbgPrintf("suitableImage(), bootPrefix='%s', type='%s'\n", + bootPrefix, line->elements[0].item); fullName = alloca(strlen(bootPrefix) + strlen(line->elements[1].item) + 1); rootspec = getRootSpecifier(line->elements[1].item); + if (rootspec == NULL) { + rootspec = getSubvolPrefix(entry->lines, line->elements[1].item); + } int rootspec_offset = rootspec ? strlen(rootspec) : 0; int hasslash = endswith(bootPrefix, '/') || beginswith(line->elements[1].item + rootspec_offset, '/'); sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/", line->elements[1].item + rootspec_offset); + dbgPrintf("suitbleImage(): fullName='%s' root/subvol prefix='%s'\n", + fullName, (rootspec != NULL) ? rootspec : ""); if (access(fullName, R_OK)) { notSuitablePrintf(entry, 0, "access to %s failed\n", fullName); return 0; @@ -2052,11 +2112,17 @@ struct singleEntry * findEntryByPath(struct grubConfig * config, if (line && line->type != LT_MENUENTRY && line->numElements >= 2) { rootspec = getRootSpecifier(line->elements[1].item); + if (rootspec == NULL) { + rootspec = getSubvolPrefix(entry->lines, line->elements[1].item); + } if (!strcmp(line->elements[1].item + ((rootspec != NULL) ? strlen(rootspec) : 0), kernel + strlen(prefix))) break; } + if(line->type == LT_MENUENTRY) + dbgPrintf("findEntryByPath: got:'%s', wanted='%s'\n", + line->elements[1].item, kernel); if(line->type == LT_MENUENTRY && !strcmp(line->elements[1].item, kernel)) break; @@ -2201,7 +2267,7 @@ struct singleEntry * findTemplate(struct grubConfig * cfg, const char * prefix, return NULL; } -char * findBootPrefix(void) { +static char * findBootPrefix(void) { struct stat sb, sb2; stat("/", &sb); @@ -2828,17 +2894,23 @@ struct singleLine * addLineTmpl(struct singleEntry * entry, /* 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|LT_KERNEL_16|LT_INITRD_16)) { char * rootspec = getRootSpecifier(tmplLine->elements[1].item); + if ((rootspec == NULL) && (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16))) { + rootspec = getSubvolPrefix(entry->lines, tmplLine->elements[1].item); + } if (rootspec != NULL) { free(newLine->elements[1].item); newLine->elements[1].item = sdupprintf("%s%s", rootspec, val); } } + dbgPrintf("addLineTmpl(%s), type= 0x%x '%s'\n", + newLine->elements[0].item, tmplLine->type, + newLine->elements[1].item); + } else { + dbgPrintf("addLineTmpl(%s), type= 0x%x\n", newLine->numElements ? + newLine->elements[0].item : "", tmplLine->type); } - dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ? - newLine->elements[0].item : ""); - if (!entry->lines) { /* first one on the list */ entry->lines = newLine; @@ -3357,23 +3429,40 @@ int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel, struct singleEntry * entry; struct singleLine * line, * kernelLine, *endLine = NULL; int index = 0; + char * svPrefix = NULL; + char * newInitrd = NULL; if (!image) return 0; + dbgPrintf("addMBInitrd(), image='%s', prefix='%s', initrd='%s'\n", + image, prefix, initrd); for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) { kernelLine = getLineByType(LT_MBMODULE, entry->lines); if (!kernelLine) continue; + dbgPrintf("... index=%i, kernel: %s '%s'\n", index, + kernelLine->elements[0].item, + kernelLine->elements[1].item); + svPrefix = getSubvolPrefix(entry->lines, kernelLine->elements[1].item); if (prefix) { int prefixLen = strlen(prefix); if (!strncmp(initrd, prefix, prefixLen)) initrd += prefixLen; } + if (svPrefix) { + newInitrd = alloca(strlen(svPrefix) + strlen(initrd) + 2); + strcpy(newInitrd, svPrefix); + strcat(newInitrd, initrd); + } else + newInitrd = (char *)initrd; + dbgPrintf("... updated initrd='%s'\n", newInitrd); 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); + kernelLine->indent, newInitrd); + if (svPrefix) + free(svPrefix); if (!line) return 1; if (endLine) { @@ -3393,12 +3482,20 @@ int updateInitrd(struct grubConfig * cfg, const char * image, struct singleEntry * entry; struct singleLine * line, * kernelLine, *endLine = NULL; int index = 0; + char * svPrefix = NULL; + char * newInitrd = NULL; if (!image) return 0; + dbgPrintf("updateInitrd(), image='%s', prefix='%s', initrd='%s'\n", + image, prefix, initrd); for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) { kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines); if (!kernelLine) continue; + dbgPrintf("... index=%i, kernel: %s '%s'\n", index, + kernelLine->elements[0].item, + kernelLine->elements[1].item); + svPrefix = getSubvolPrefix(entry->lines, kernelLine->elements[1].item); line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines); if (line) @@ -3408,6 +3505,13 @@ int updateInitrd(struct grubConfig * cfg, const char * image, if (!strncmp(initrd, prefix, prefixLen)) initrd += prefixLen; } + if (svPrefix) { + newInitrd = alloca(strlen(svPrefix) + strlen(initrd) + 2); + strcpy(newInitrd, svPrefix); + strcat(newInitrd, initrd); + } else + newInitrd = (char *)initrd; + dbgPrintf("... updated initrd='%s'\n", newInitrd); endLine = getLineByType(LT_ENTRY_END, entry->lines); if (endLine) removeLine(entry, endLine); @@ -3425,7 +3529,9 @@ int updateInitrd(struct grubConfig * cfg, const char * image, default: lt = preferredLineType(LT_INITRD, cfg->cfi); } - line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd); + line = addLine(entry, cfg->cfi, lt, kernelLine->indent, newInitrd); + if (svPrefix) + free(svPrefix); if (!line) return 1; if (endLine) { @@ -3790,6 +3896,7 @@ int addNewKernel(struct grubConfig * config, struct singleEntry * template, struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL; int needs; char * chptr; + char * svPrefix = NULL; if (!newKernelPath) return 0; @@ -3885,6 +3992,8 @@ int addNewKernel(struct grubConfig * config, struct singleEntry * template, newLine = addLineTmpl(new, tmplLine, newLine, newKernelPath + strlen(prefix), config->cfi); needs &= ~NEED_KERNEL; + /* save svPrefix in case we need to do initrd */ + svPrefix = getSubvolPrefix(new->lines, tmplLine->elements[1].item); } } else if (tmplLine->type == LT_HYPER && @@ -3962,9 +4071,16 @@ int addNewKernel(struct grubConfig * config, struct singleEntry * template, needs &= ~NEED_INITRD; } } else if (needs & NEED_INITRD) { - char *initrdVal; + char *initrdVal, *newInitrdVal = NULL; initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount); - newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi); + if (svPrefix) { + newInitrdVal = alloca(strlen(svPrefix) + strlen(initrdVal)); + strcpy(newInitrdVal, svPrefix); + strcat(newInitrdVal, initrdVal); + } + else + newInitrdVal = initrdVal; + newLine = addLineTmpl(new, tmplLine, newLine, newInitrdVal, config->cfi); free(initrdVal); needs &= ~NEED_INITRD; } -- 1.9.3 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list