[PATCH 2/9] v2.2 add support for btrfs when grub2 is bootloader

Gene Czarcinski gczarcinski at ec.rr.com
Mon Sep 15 12:50:45 UTC 2014


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



More information about the anaconda-patches mailing list