[Fedora-xen] [PATCH 2 of 6] Add new generic functions

Aron Griffis aron at hp.com
Thu Jun 29 21:42:34 UTC 2006


# HG changeset patch
# User agriffis at cheo.zko.hp.com
# Node ID 42e7d064ab2666bad84fc61f0465bee4f7c79d65
# Parent  8bbf845cad0dc1774c348f036d4eaa0365aef7e9
Add new generic functions

This patch adds some generic functions to make extending grubby a
little easier, and makes changes throughout the code to take advantage
of them.

- new function for duplicating a line (deep copy):
    dupLine

- new functions for manipulating singleLine->element arrays:
    insertElement
    removeElement

- new functions for matching keywords to types:
    getKeywordByType
    getTypeByKeyword

- new functions for search an entry for lines matching a bitmask of
  types:
    getLineByType

- new function for inserting a line to an entry from a template:
    addLineTmpl

- simple debugging via dbgPrintf, which is normally compiled out

Grubby builds with this patch and introduces no regressions.

Signed-off-by: Aron Griffis <aron at hp.com>

 grubby.c |  452 ++++++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 287 insertions(+), 165 deletions(-)

diff -r 8bbf845cad0d -r 42e7d064ab26 grubby/grubby.c
--- a/grubby/grubby.c	Thu Jun 29 12:21:58 2006 -0400
+++ b/grubby/grubby.c	Thu Jun 29 16:10:13 2006 -0400
@@ -31,6 +31,14 @@
 
 #include "block.h"
 
+#define DEBUG 0
+
+#if DEBUG
+#define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
+#else
+#define dbgPrintf(format, args...)
+#endif
+
 #define _(A) (A)
 
 #define CODE_SEG_SIZE	  128	/* code segment checked by --bootloader-probe */
@@ -41,9 +49,23 @@ struct lineElement {
     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 = 1 << 0,
+    LT_TITLE      = 1 << 1,
+    LT_KERNEL     = 1 << 2,
+    LT_INITRD     = 1 << 3,
+    LT_DEFAULT    = 1 << 5,
+    LT_MBMODULE   = 1 << 6,
+    LT_ROOT       = 1 << 7,
+    LT_FALLBACK   = 1 << 8,
+    LT_KERNELARGS = 1 << 9,
+    LT_BOOT       = 1 << 10,
+    LT_BOOTROOT   = 1 << 11,
+    LT_LBA        = 1 << 12,
+    LT_OTHER      = 1 << 13,
+    LT_GENERIC    = 1 << 14,
+    LT_UNKNOWN    = 1 << 15,
+};
 
 struct singleLine {
     char * indent;
@@ -77,7 +99,7 @@ struct keywordTypes {
     char * key;
     enum lineType_e type;
     char nextChar;
-} ;
+};
 
 struct configFileInfo {
     char * defaultConfig;
@@ -258,19 +280,28 @@ struct grubConfig {
     struct configFileInfo * cfi;
 };
 
-
 struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
 struct singleEntry * findEntryByPath(struct grubConfig * cfg, 
 				     const char * path, const char * prefix,
 				     int * index);
 static int readFile(int fd, char ** bufPtr);
 static void lineInit(struct singleLine * line);
+struct singleLine * lineDup(struct singleLine * line);
 static void lineFree(struct singleLine * line);
 static int lineWrite(FILE * out, struct singleLine * line,
 		     struct configFileInfo * cfi);
 static int getNextLine(char ** bufPtr, struct singleLine * line,
 		       struct configFileInfo * cfi);
 static char * getRootSpecifier(char * str);
+static void insertElement(struct singleLine * line,
+			  const char * item, int insertHere);
+static void removeElement(struct singleLine * line, int removeHere);
+static struct keywordTypes * getKeywordByType(enum lineType_e type,
+					      struct configFileInfo * cfi);
+static enum lineType_e getTypeByKeyword(char * keyword, 
+					struct configFileInfo * cfi);
+static struct singleLine * getLineByType(enum lineType_e type,
+					 struct singleLine * line);
 
 static char * sdupprintf(const char *format, ...)
 #ifdef __GNUC__
@@ -305,8 +336,40 @@ static char * sdupprintf(const char *for
     return buf;
 }
 
+static struct keywordTypes * getKeywordByType(enum lineType_e type,
+					      struct configFileInfo * cfi) {
+    struct keywordTypes * kw;
+    for (kw = cfi->keywords; kw->key; kw++) {
+	if (kw->type == type)
+	    return kw;
+    }
+    return NULL;
+}
+
+static enum lineType_e getTypeByKeyword(char * keyword, 
+					struct configFileInfo * cfi) {
+    struct keywordTypes * kw;
+    for (kw = cfi->keywords; kw->key; kw++) {
+	if (!strcmp(keyword, kw->key))
+	    return kw->type;
+    }
+    return LT_UNKNOWN;
+}
+
+static struct singleLine * getLineByType(enum lineType_e type,
+					 struct singleLine * line) {
+    dbgPrintf("getLineByType(%d): ", type);
+    for (; line; line = line->next) {
+	dbgPrintf("%d:%s ", line->type, 
+		  line->numElements ? line->elements[0].item : "(empty)");
+	if (line->type & type) break;
+    }
+    dbgPrintf(line ? "\n" : " (failed)\n");
+    return line;
+}
+
 static int isBracketedTitle(struct singleLine * line) {
-    if ((*line->elements[0].item == '[') && (line->numElements == 1)) {
+    if (line->numElements == 1 && *line->elements[0].item == '[') {
         int len = strlen(line->elements[0].item);
         if (*(line->elements[0].item + len - 1) == ']') {
             /* FIXME: this is a hack... */
@@ -318,19 +381,10 @@ static int isBracketedTitle(struct singl
     return 0;
 }
 
-/* figure out if this is a entry separator */
 static int isEntrySeparator(struct singleLine * line,
                             struct configFileInfo * cfi) {
-    if (line->type == LT_WHITESPACE)
-	return 0;
-    if (line->type == cfi->entrySeparator)
-        return 1;
-    if (line->type == LT_OTHER)
-        return 1;
-    if (cfi->titleBracketed && isBracketedTitle(line)) {
-        return 1;
-    }
-    return 0;
+    return line->type == cfi->entrySeparator || line->type == LT_OTHER ||
+	(cfi->titleBracketed && isBracketedTitle(line));
 }
 
 /* extract the title from within brackets (for zipl) */
@@ -381,6 +435,25 @@ static void lineInit(struct singleLine *
     line->next = NULL;
 }
 
+struct singleLine * lineDup(struct singleLine * line) {
+    int i;
+    struct singleLine * newLine = malloc(sizeof(*newLine));
+
+    newLine->indent = strdup(line->indent);
+    newLine->next = NULL;
+    newLine->type = line->type;
+    newLine->numElements = line->numElements;
+    newLine->elements = malloc(sizeof(*newLine->elements) * 
+			       newLine->numElements);
+
+    for (i = 0; i < newLine->numElements; i++) {
+	newLine->elements[i].indent = strdup(line->elements[i].indent);
+	newLine->elements[i].item = strdup(line->elements[i].item);
+    }
+
+    return newLine;
+}
+
 static void lineFree(struct singleLine * line) {
     int i;
 
@@ -425,9 +498,7 @@ static int getNextLine(char ** bufPtr, s
     char * chptr;
     int elementsAlloced = 0;
     struct lineElement * element;
-    struct keywordTypes * keywords = cfi->keywords;
     int first = 1;
-    int i;
 
     lineFree(line);
 
@@ -481,14 +552,8 @@ static int getNextLine(char ** bufPtr, s
     if (!line->numElements)
 	line->type = LT_WHITESPACE;
     else {
-	for (i = 0; keywords[i].key; i++) 
-	    if (!strcmp(line->elements[0].item, keywords[i].key)) break;
-
-	if (keywords[i].key) {
-	    line->type = keywords[i].type;
-	} else {
-	    line->type = LT_UNKNOWN;
-            
+	line->type = getTypeByKeyword(line->elements[0].item, cfi);
+	if (line->type == LT_UNKNOWN) {
             /* zipl does [title] instead of something reasonable like all
              * the other boot loaders.  kind of ugly */
             if (cfi->titleBracketed && isBracketedTitle(line)) {
@@ -761,8 +826,7 @@ static void writeDefault(FILE * out, cha
 
 	    if (!entry) return;
 
-	    line = entry->lines;
-	    while (line && line->type != LT_TITLE) line = line->next;
+	    line = getLineByType(LT_TITLE, entry->lines);
 
 	    if (line && line->numElements >= 2)
 		fprintf(out, "%sdefault%s%s\n", indent, separator, 
@@ -913,12 +977,10 @@ int suitableImage(struct singleEntry * e
     char * dev;
     char * rootspec;
 
-    line = entry->lines;
-    while (line && line->type != LT_KERNEL) line = line->next;
-    
-    if (!line) return 0;
     if (skipRemoved && entry->skip) return 0;
-    if (line->numElements < 2) return 0;
+
+    line = getLineByType(LT_KERNEL, entry->lines);
+    if (!line || line->numElements < 2) return 0;
 
     if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
 
@@ -926,8 +988,7 @@ int suitableImage(struct singleEntry * e
 		      strlen(line->elements[1].item) + 1);
     rootspec = getRootSpecifier(line->elements[1].item);
     sprintf(fullName, "%s%s", bootPrefix, 
-            line->elements[1].item + ((rootspec != NULL) ? 
-                                      strlen(rootspec) : 0));
+            line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
     if (access(fullName, R_OK)) return 0;
 
     for (i = 2; i < line->numElements; i++) 
@@ -936,19 +997,15 @@ int suitableImage(struct singleEntry * e
 	dev = line->elements[i].item + 5;
     } else {
 	/* look for a lilo style LT_ROOT line */
-	line = entry->lines;
-	while (line && line->type != LT_ROOT) line = line->next;
+	line = getLineByType(LT_ROOT, entry->lines);
 
 	if (line && line->numElements >= 2) {
 	    dev = line->elements[1].item;
 	} else {
-            int type;
-	    /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */
-	    line = entry->lines;
-
-            type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);
-
-	    while (line && line->type != type) line = line->next;
+	    /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
+	     * grub+multiboot uses LT_MBMODULE for the args, so check that too.
+	     */
+	    line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
 
             /* failed to find one */
             if (!line) return 0;
@@ -1019,10 +1076,7 @@ struct singleEntry * findEntryByPath(str
 	entry = findEntryByIndex(config, indexVars[i]);
 	if (!entry) return NULL;
 
-	line = entry->lines;
-	while (line && line->type != LT_KERNEL)
-	    line = line->next;
-
+	line = getLineByType(LT_KERNEL, entry->lines);
 	if (!line) return NULL;
 
 	if (index) *index = indexVars[i];
@@ -1064,47 +1118,35 @@ struct singleEntry * findEntryByPath(str
 	    kernel += 6;
 	}
 
-	while ((entry = findEntryByIndex(config, i))) {
-	    line = entry->lines;
-	    while (line && line->type != checkType) line=line->next;
-
-
-	    if (line && line->numElements >= 2 && !entry->skip) {
-                rootspec = getRootSpecifier(line->elements[1].item);
-	        if (!strcmp(line->elements[1].item  + 
-                            ((rootspec != NULL) ? strlen(rootspec) : 0),
-                            kernel + strlen(prefix)))
-                    break;
-            }
-            
-            /* have to check multiboot lines too */
-            if (entry->multiboot) {
-                while (line && line->type != LT_MBMODULE) line = line->next;
-                if (line && line->numElements >= 2 && !entry->skip) {
-                    rootspec = getRootSpecifier(line->elements[1].item);
-                    if (!strcmp(line->elements[1].item  + 
-                                ((rootspec != NULL) ? strlen(rootspec) : 0),
-                                kernel + strlen(prefix)))
-                        break;
-                }
-            }
-
-	    i++;
+	for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
+	    if (entry->skip) continue;
+
+	    dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
+
+	    /* check all the lines matching checkType */
+	    for (line = entry->lines; line; line = line->next) {
+		line = getLineByType(entry->multiboot && checkType == LT_KERNEL ? 
+				     LT_KERNEL|LT_MBMODULE : checkType, line);
+		if (!line) break;  /* not found in this entry */
+
+		if (line && line->numElements >= 2) {
+		    rootspec = getRootSpecifier(line->elements[1].item);
+		    if (!strcmp(line->elements[1].item + 
+				((rootspec != NULL) ? strlen(rootspec) : 0),
+				kernel + strlen(prefix)))
+			break;
+		}
+	    }
+
+	    /* make sure this entry has a kernel identifier; this skips
+	     * non-Linux boot entries (could find netbsd etc, though, which is
+	     * unfortunate)
+	     */
+	    if (line && getLineByType(LT_KERNEL, entry->lines))
+		break; /* found 'im! */
 	}
 
 	if (index) *index = i;
-    }
-
-    if (!entry) return NULL;
-
-    /* make sure this entry has a kernel identifier; this skips non-Linux
-       boot entries (could find netbsd etc, though, which is unfortunate) */
-    line = entry->lines;
-    while (line && line->type != LT_KERNEL) line = line->next;
-    if (!line) {
-	if (!index) index = &i;
-	(*index)++;
-	return findEntryByPath(config, kernel, prefix, index);
     }
 
     return entry;
@@ -1271,11 +1313,9 @@ void displayEntry(struct singleEntry * e
     char * root = NULL;
     int i;
 
-    line = entry->lines;
-    while (line && line->type != LT_KERNEL) line = line->next;
-
     printf("index=%d\n", index);
 
+    line = getLineByType(LT_KERNEL, entry->lines);
     printf("kernel=%s\n", line->elements[1].item);
 
     if (line->numElements >= 3) {
@@ -1293,9 +1333,7 @@ void displayEntry(struct singleEntry * e
 	}
 	printf("\"\n");
     } else {
-	line = entry->lines;
-	while (line && line->type != LT_KERNELARGS) line=line->next;
-	
+	line = getLineByType(LT_KERNELARGS, entry->lines);
 	if (line) {
 	    char * s;
 
@@ -1319,9 +1357,7 @@ void displayEntry(struct singleEntry * e
     }
 
     if (!root) {
-	line = entry->lines;
-	while (line && line->type != LT_ROOT) line = line->next;
-
+	line = getLineByType(LT_ROOT, entry->lines);
 	if (line && line->numElements >= 2)
 	    root=line->elements[1].item;
     }
@@ -1336,8 +1372,7 @@ void displayEntry(struct singleEntry * e
 	printf("root=%s\n", s);
     }
 
-    line = entry->lines;
-    while (line && line->type != LT_INITRD) line = line->next;
+    line = getLineByType(LT_INITRD, entry->lines);
 
     if (line && line->numElements >= 2) {
 	printf("initrd=%s", prefix);
@@ -1421,14 +1456,12 @@ int displayInfo(struct grubConfig * conf
     if (config->cfi == &grubConfigType) {
 	dumpSysconfigGrub();
     } else {
-	line = config->theLines;
-	while (line && line->type != LT_BOOT) line = line->next;
+	line = getLineByType(LT_BOOT, config->theLines);
 	if (line && line->numElements >= 1) {
 	    printf("boot=%s\n", line->elements[1].item);
 	}
 
-	line = config->theLines;
-	while (line && line->type != LT_LBA) line = line->next;
+	line = getLineByType(LT_LBA, config->theLines);
 	if (line) printf("lba\n");
     }
 
@@ -1443,77 +1476,100 @@ int displayInfo(struct grubConfig * conf
     return 0;
 }
 
+struct singleLine * addLineTmpl(struct singleEntry * entry,
+				struct singleLine * tmplLine,
+				struct singleLine * prevLine,
+				const char * val) {
+    struct singleLine * newLine = lineDup(tmplLine);
+
+    if (val) {
+	/* override the inherited value with our own.
+	 * This is a little weak because it only applies to elements[1]
+	 */
+	if (newLine->numElements > 1)
+	    removeElement(newLine, 1);
+	insertElement(newLine, val, 1);
+
+	/* but try to keep the rootspec from the template... sigh */
+	if (tmplLine->type & (LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
+	    char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
+	    if (rootspec != NULL) {
+		free(newLine->elements[1].item);
+		newLine->elements[1].item = 
+		    sdupprintf("%s%s", rootspec, val);
+	    }
+	}
+    }
+
+    dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ? 
+	      newLine->elements[0].item : "");
+
+    if (!entry->lines) {
+	/* first one on the list */
+	entry->lines = newLine;
+    } else if (prevLine) {
+	/* add after prevLine */
+	newLine->next = prevLine->next;
+	prevLine->next = newLine;
+    }
+
+    return newLine;
+}
+
 /* val may be NULL */
 struct singleLine *  addLine(struct singleEntry * entry, 
 			     struct configFileInfo * cfi, 
-			     enum lineType_e type, const char * defaultIndent,
-			     char * val) {
+			     enum lineType_e type, char * defaultIndent,
+			     const char * val) {
     struct singleLine * line, * prev;
-    int i;
-
-    for (i = 0; cfi->keywords[i].key; i++)
-	if (cfi->keywords[i].type == type) break;
-    if (type != LT_TITLE || !cfi->titleBracketed) 
-        if (!cfi->keywords[i].key) abort();
+    struct keywordTypes * kw;
+    struct singleLine tmpl;
+
+    /* NB: This function shouldn't allocate items on the heap, rather on the
+     * stack since it calls addLineTmpl which will make copies.
+     */
+
+    if (type == LT_TITLE && cfi->titleBracketed) {
+	/* we're doing a bracketed title (zipl) */
+	tmpl.type = type;
+	tmpl.numElements = 1;
+	tmpl.elements = alloca(sizeof(*tmpl.elements));
+	tmpl.elements[0].item = alloca(strlen(val)+3);
+	sprintf(tmpl.elements[0].item, "[%s]", val);
+	tmpl.elements[0].indent = "";
+	val = NULL;
+    } else {
+	kw = getKeywordByType(type, cfi);
+	if (!kw) abort();
+	tmpl.type = type;
+	tmpl.numElements = val ? 2 : 1;
+	tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
+	tmpl.elements[0].item = kw->key;
+	tmpl.elements[0].indent = alloca(2);
+	sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
+	if (val) {
+	    tmpl.elements[1].item = (char *)val;
+	    tmpl.elements[1].indent = "";
+	}
+    }
 
     /* The last non-empty line gives us the indention to us and the line
        to insert after. Note that comments are considered empty lines, which
        may not be ideal? If there are no lines or we are looking at the
        first line, we use defaultIndent (the first line is normally indented
        differently from the rest) */ 
-    if (entry->lines) {
-	line = entry->lines;
-	prev = NULL;
-	while (line) {
-	    if (line->numElements) prev = line;
-	    line = line->next;
-	}
-	if (!prev) {
-	    /* just use the last line */
-	    prev = entry->lines;
-	    while (prev->next) prev = prev->next;
-	}
-
-	line = prev->next;
-	prev->next = malloc(sizeof(*line));
-	prev->next->next = line;
-	line = prev->next;
-
-	if (prev == entry->lines)
-	    line->indent = strdup(defaultIndent);
-	else
-	    line->indent = strdup(prev->indent);
-    } else {
-	line = malloc(sizeof(*line));
-	line->indent = strdup(defaultIndent);
-	line->next = NULL;
-    }
-
-    if (type != LT_TITLE || !cfi->titleBracketed) {
-        line->type = type;
-        line->numElements = val ? 2 : 1;
-        line->elements = malloc(sizeof(*line->elements) * line->numElements);
-        line->elements[0].item = strdup(cfi->keywords[i].key);
-        line->elements[0].indent = malloc(2);
-        line->elements[0].indent[0] = cfi->keywords[i].nextChar;
-        line->elements[0].indent[1] = '\0';
-        
-        if (val) {
-            line->elements[1].item = val;
-            line->elements[1].indent = strdup("");
-        }
-    } else {
-        /* we're doing the title of a bracketed title (zipl) */
-        line->type = type;
-        line->numElements = 1;
-        line->elements = malloc(sizeof(*line->elements) * line->numElements);
-
-        line->elements[0].item = malloc(strlen(val) + 3);
-        sprintf(line->elements[0].item, "[%s]", val);
-        line->elements[0].indent = strdup("");
-    }
-
-    return line;
+    for (line = entry->lines, prev = NULL; line; line = line->next) {
+	if (line->numElements) prev = line;
+	/* fall back on the last line if prev isn't otherwise set */
+	if (!line->next && !prev) prev = line;
+    }
+
+    if (prev == entry->lines)
+	tmpl.indent = defaultIndent ?: "";
+    else
+	tmpl.indent = prev->indent;
+
+    return addLineTmpl(entry, &tmpl, prev, val);
 }
 
 void removeLine(struct singleEntry * entry, struct singleLine * line) {
@@ -1536,6 +1592,73 @@ void removeLine(struct singleEntry * ent
     }
 
     free(line);
+}
+
+static void insertElement(struct singleLine * line,
+			  const char * item, int insertHere) {
+
+    /* sanity check */
+    if (insertHere > line->numElements) {
+	dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
+		  insertHere, line->numElements);
+	insertHere = line->numElements;
+    }
+
+    line->elements = realloc(line->elements, (line->numElements + 1) * 
+			     sizeof(*line->elements));
+    memmove(&line->elements[insertHere+1], 
+	    &line->elements[insertHere], 
+	    (line->numElements - insertHere) * 
+	    sizeof(*line->elements));
+    line->elements[insertHere].item = strdup(item);
+
+    if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
+	/* move the end-of-line forward */
+	line->elements[insertHere].indent = 
+	    line->elements[insertHere-1].indent;
+	line->elements[insertHere-1].indent = strdup(" ");
+    } else {
+	/* technically this should honor nextChar from keywordTypes 
+	 * when insertHere == 0, but oh well
+	 */
+	line->elements[insertHere].indent = 
+	    strdup(insertHere == line->numElements ? "" : " ");
+    }
+
+    line->numElements++;
+
+    dbgPrintf("insertElement(%s, '%s%s', %d)\n",
+	      line->elements[0].item,
+	      line->elements[insertHere].item,
+	      line->elements[insertHere].indent,
+	      insertHere);
+}
+
+static void removeElement(struct singleLine * line, int removeHere) {
+    int i;
+
+    /* sanity check */
+    if (removeHere >= line->numElements) return;
+
+    dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item, 
+	      removeHere, line->elements[removeHere].item);
+
+    free(line->elements[removeHere].item);
+
+    if (removeHere > 1) {
+	/* previous argument gets this argument's post-indentation */
+	free(line->elements[removeHere-1].indent);
+	line->elements[removeHere-1].indent =
+	    line->elements[removeHere].indent;
+    } else {
+	free(line->elements[removeHere].indent);
+    }
+
+    /* now collapse the array, but don't bother to realloc smaller */
+    for (i = removeHere; i < line->numElements - 1; i++)
+	line->elements[i] = line->elements[i + 1];
+
+    line->numElements--;
 }
 
 int argMatch(const char * one, const char * two) {
@@ -2546,8 +2669,7 @@ int main(int argc, const char ** argv) {
 	if (!entry) return 0;
 	if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
 
-	line = entry->lines;
-	while (line && line->type != LT_KERNEL) line = line->next;
+	line = getLineByType(LT_KERNEL, entry->lines);
 	if (!line) return 0;
 
         rootspec = getRootSpecifier(line->elements[1].item);




More information about the Fedora-xen mailing list