Magellan Linux

Diff of /tags/grubby-8_32/grubby.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 914 by niro, Wed Oct 28 00:16:16 2009 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39    #define DEBUG 0
40    
41  #include "mount_by_label.h"  #if DEBUG
42    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
43    #else
44    #define dbgPrintf(format, args...)
45    #endif
46    
47  #define _(A) (A)  #define _(A) (A)
48    
49    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
50  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
51    
52  /* comments get lumped in with indention */  /* comments get lumped in with indention */
# Line 38  struct lineElement { Line 55  struct lineElement {
55      char * indent;      char * indent;
56  };  };
57    
58  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
59         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE = 1 << 0,
60         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE      = 1 << 1,
61        LT_KERNEL     = 1 << 2,
62        LT_INITRD     = 1 << 3,
63        LT_HYPER      = 1 << 4,
64        LT_DEFAULT    = 1 << 5,
65        LT_MBMODULE   = 1 << 6,
66        LT_ROOT       = 1 << 7,
67        LT_FALLBACK   = 1 << 8,
68        LT_KERNELARGS = 1 << 9,
69        LT_BOOT       = 1 << 10,
70        LT_BOOTROOT   = 1 << 11,
71        LT_LBA        = 1 << 12,
72        LT_OTHER      = 1 << 13,
73        LT_GENERIC    = 1 << 14,
74        LT_UNKNOWN    = 1 << 15,
75    };
76    
77  struct singleLine {  struct singleLine {
78      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 93  struct singleEntry {
93    
94  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */
95    
96  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
97  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
98  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
99  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
100  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
101    #define NEED_MB      (1 << 4)
102    
103  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
104  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 74  struct keywordTypes { Line 107  struct keywordTypes {
107      char * key;      char * key;
108      enum lineType_e type;      enum lineType_e type;
109      char nextChar;      char nextChar;
110  } ;      char separatorChar;
111    };
112    
113  struct configFileInfo {  struct configFileInfo {
114      char * defaultConfig;      char * defaultConfig;
# Line 86  struct configFileInfo { Line 120  struct configFileInfo {
120      int argsInQuotes;      int argsInQuotes;
121      int maxTitleLength;      int maxTitleLength;
122      int titleBracketed;      int titleBracketed;
123        int mbHyperFirst;
124        int mbInitRdIsModule;
125        int mbConcatArgs;
126        int mbAllowExtraInitRds;
127  };  };
128    
129  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 132  struct keywordTypes grubKeywords[] = {
132      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
133      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
134      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
135      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
136      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
137        { "kernel",     LT_HYPER,       ' ' },
138      { NULL,    0, 0 },      { NULL,    0, 0 },
139  };  };
140    
141  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
142      "/boot/grub/grub.conf",    /* defaultConfig */      "/etc/grub.conf",    /* defaultConfig */
143      grubKeywords,    /* keywords */      grubKeywords,    /* keywords */
144      1,    /* defaultIsIndex */      1,    /* defaultIsIndex */
145      1,    /* defaultSupportSaved */      1,    /* defaultSupportSaved */
# Line 109  struct configFileInfo grubConfigType = { Line 148  struct configFileInfo grubConfigType = {
148      0,    /* argsInQuotes */      0,    /* argsInQuotes */
149      0,    /* maxTitleLength */      0,    /* maxTitleLength */
150      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
151        1,                                      /* mbHyperFirst */
152        1,                                      /* mbInitRdIsModule */
153        0,                                      /* mbConcatArgs */
154        1,                                      /* mbAllowExtraInitRds */
155  };  };
156    
157  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 185  struct keywordTypes yabootKeywords[] = {
185      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
186      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
187      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
188      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
189      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
190      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
191      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 205  struct keywordTypes liloKeywords[] = {
205      { NULL,    0, 0 },      { NULL,    0, 0 },
206  };  };
207    
208    struct keywordTypes eliloKeywords[] = {
209        { "label",    LT_TITLE,    '=' },
210        { "root",    LT_ROOT,    '=' },
211        { "default",    LT_DEFAULT,    '=' },
212        { "image",    LT_KERNEL,    '=' },
213        { "initrd",    LT_INITRD,    '=' },
214        { "append",    LT_KERNELARGS,  '=' },
215        { "vmm",    LT_HYPER,       '=' },
216        { NULL,    0, 0 },
217    };
218    
219  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
220      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
221      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 237  struct keywordTypes ziplKeywords[] = {
237      { NULL,         0, 0 },      { NULL,         0, 0 },
238  };  };
239    
240    struct keywordTypes extlinuxKeywords[] = {
241        { "label",    LT_TITLE,    ' ' },
242        { "root",    LT_ROOT,    ' ' },
243        { "default",    LT_DEFAULT,    ' ' },
244        { "kernel",    LT_KERNEL,    ' ' },
245        { "initrd",    LT_INITRD,      ' ', ',' },
246        { "append",    LT_KERNELARGS,  ' ' },
247        { "prompt",     LT_UNKNOWN,     ' ' },
248        { NULL,    0, 0 },
249    };
250    int useextlinuxmenu;
251  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
252      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */
253      liloKeywords,    /* keywords */      eliloKeywords,    /* keywords */
254      0,    /* defaultIsIndex */      0,    /* defaultIsIndex */
255      0,    /* defaultSupportSaved */      0,    /* defaultSupportSaved */
256      LT_KERNEL,    /* entrySeparator */      LT_KERNEL,    /* entrySeparator */
# Line 193  struct configFileInfo eliloConfigType = Line 258  struct configFileInfo eliloConfigType =
258      1,    /* argsInQuotes */      1,    /* argsInQuotes */
259      0,    /* maxTitleLength */      0,    /* maxTitleLength */
260      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
261        0,                                      /* mbHyperFirst */
262        0,                                      /* mbInitRdIsModule */
263        1,                                      /* mbConcatArgs */
264        0,                                      /* mbAllowExtraInitRds */
265  };  };
266    
267  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
# Line 205  struct configFileInfo liloConfigType = { Line 274  struct configFileInfo liloConfigType = {
274      1,    /* argsInQuotes */      1,    /* argsInQuotes */
275      15,    /* maxTitleLength */      15,    /* maxTitleLength */
276      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
277        0,                                      /* mbHyperFirst */
278        0,                                      /* mbInitRdIsModule */
279        0,                                      /* mbConcatArgs */
280        0,                                      /* mbAllowExtraInitRds */
281  };  };
282    
283  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
# Line 217  struct configFileInfo yabootConfigType = Line 290  struct configFileInfo yabootConfigType =
290      1,    /* argsInQuotes */      1,    /* argsInQuotes */
291      15,    /* maxTitleLength */      15,    /* maxTitleLength */
292      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
293        0,                                      /* mbHyperFirst */
294        0,                                      /* mbInitRdIsModule */
295        0,                                      /* mbConcatArgs */
296        1,                                      /* mbAllowExtraInitRds */
297  };  };
298    
299  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
# Line 229  struct configFileInfo siloConfigType = { Line 306  struct configFileInfo siloConfigType = {
306      1,    /* argsInQuotes */      1,    /* argsInQuotes */
307      15,    /* maxTitleLength */      15,    /* maxTitleLength */
308      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
309        0,                                      /* mbHyperFirst */
310        0,                                      /* mbInitRdIsModule */
311        0,                                      /* mbConcatArgs */
312        0,                                      /* mbAllowExtraInitRds */
313  };  };
314    
315  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
# Line 239  struct configFileInfo ziplConfigType = { Line 320  struct configFileInfo ziplConfigType = {
320      LT_TITLE,    /* entrySeparator */      LT_TITLE,    /* entrySeparator */
321      0,    /* needsBootPrefix */      0,    /* needsBootPrefix */
322      1,    /* argsInQuotes */      1,    /* argsInQuotes */
323      15,    /* maxTitleLength */      0,    /* maxTitleLength */
324      1,                                      /* titleBracketed */      1,                                      /* titleBracketed */
325        0,                                      /* mbHyperFirst */
326        0,                                      /* mbInitRdIsModule */
327        0,                                      /* mbConcatArgs */
328        0,                                      /* mbAllowExtraInitRds */
329    };
330    
331    struct configFileInfo extlinuxConfigType = {
332        "/boot/extlinux/extlinux.conf",         /* defaultConfig */
333        extlinuxKeywords,                       /* keywords */
334        0,                                      /* defaultIsIndex */
335        0,                                      /* defaultSupportSaved */
336        LT_TITLE,                               /* entrySeparator */
337        1,                                      /* needsBootPrefix */
338        0,                                      /* argsInQuotes */
339        255,                                    /* maxTitleLength */
340        0,                                      /* titleBracketed */
341        0,                                      /* mbHyperFirst */
342        0,                                      /* mbInitRdIsModule */
343        0,                                      /* mbConcatArgs */
344        1,                                      /* mbAllowExtraInitRds */
345  };  };
346    
347  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 356  struct grubConfig {
356      struct configFileInfo * cfi;      struct configFileInfo * cfi;
357  };  };
358    
   
359  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
360  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
361       const char * path, const char * prefix,       const char * path, const char * prefix,
362       int * index);       int * index);
 static char * strndup(char * from, int len);  
363  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
364  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
365    struct singleLine * lineDup(struct singleLine * line);
366  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
367  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
368       struct configFileInfo * cfi);       struct configFileInfo * cfi);
369  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
370         struct configFileInfo * cfi);         struct configFileInfo * cfi);
371  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
372    static void insertElement(struct singleLine * line,
373  static char * strndup(char * from, int len) {    const char * item, int insertHere,
374      char * to;    struct configFileInfo * cfi);
375    static void removeElement(struct singleLine * line, int removeHere);
376      to = malloc(len + 1);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
377      strncpy(to, from, len);        struct configFileInfo * cfi);
378      to[len] = '\0';  static enum lineType_e getTypeByKeyword(char * keyword,
379     struct configFileInfo * cfi);
380      return to;  static struct singleLine * getLineByType(enum lineType_e type,
381  }   struct singleLine * line);
382    static int checkForExtLinux(struct grubConfig * config);
383    struct singleLine * addLineTmpl(struct singleEntry * entry,
384                                    struct singleLine * tmplLine,
385                                    struct singleLine * prevLine,
386                                    const char * val,
387     struct configFileInfo * cfi);
388    struct singleLine *  addLine(struct singleEntry * entry,
389                                 struct configFileInfo * cfi,
390                                 enum lineType_e type, char * defaultIndent,
391                                 const char * val);
392    
393  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
394  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 423  static char * sdupprintf(const char *for
423      return buf;      return buf;
424  }  }
425    
426    static struct keywordTypes * getKeywordByType(enum lineType_e type,
427          struct configFileInfo * cfi) {
428        struct keywordTypes * kw;
429        for (kw = cfi->keywords; kw->key; kw++) {
430     if (kw->type == type)
431        return kw;
432        }
433        return NULL;
434    }
435    
436    static char * getpathbyspec(char *device) {
437        static blkid_cache blkid;
438    
439        if (!blkid)
440            blkid_get_cache(&blkid, NULL);
441    
442        return blkid_get_devname(blkid, device, NULL);
443    }
444    
445    static enum lineType_e getTypeByKeyword(char * keyword,
446     struct configFileInfo * cfi) {
447        struct keywordTypes * kw;
448        for (kw = cfi->keywords; kw->key; kw++) {
449     if (!strcmp(keyword, kw->key))
450        return kw->type;
451        }
452        return LT_UNKNOWN;
453    }
454    
455    static struct singleLine * getLineByType(enum lineType_e type,
456     struct singleLine * line) {
457        dbgPrintf("getLineByType(%d): ", type);
458        for (; line; line = line->next) {
459     dbgPrintf("%d:%s ", line->type,
460      line->numElements ? line->elements[0].item : "(empty)");
461     if (line->type & type) break;
462        }
463        dbgPrintf(line ? "\n" : " (failed)\n");
464        return line;
465    }
466    
467  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
468      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
469          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
470          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
471              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 477  static int isBracketedTitle(struct singl
477      return 0;      return 0;
478  }  }
479    
 /* figure out if this is a entry separator */  
480  static int isEntrySeparator(struct singleLine * line,  static int isEntrySeparator(struct singleLine * line,
481                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
482      if (line->type == LT_WHITESPACE)      return line->type == cfi->entrySeparator || line->type == LT_OTHER ||
483   return 0;   (cfi->titleBracketed && isBracketedTitle(line));
     if (line->type == cfi->entrySeparator)  
         return 1;  
     if (line->type == LT_OTHER)  
         return 1;  
     if (cfi->titleBracketed && isBracketedTitle(line)) {  
         return 1;  
     }  
     return 0;  
484  }  }
485    
486  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 531  static void lineInit(struct singleLine *
531      line->next = NULL;      line->next = NULL;
532  }  }
533    
534    struct singleLine * lineDup(struct singleLine * line) {
535        int i;
536        struct singleLine * newLine = malloc(sizeof(*newLine));
537    
538        newLine->indent = strdup(line->indent);
539        newLine->next = NULL;
540        newLine->type = line->type;
541        newLine->numElements = line->numElements;
542        newLine->elements = malloc(sizeof(*newLine->elements) *
543           newLine->numElements);
544    
545        for (i = 0; i < newLine->numElements; i++) {
546     newLine->elements[i].indent = strdup(line->elements[i].indent);
547     newLine->elements[i].item = strdup(line->elements[i].item);
548        }
549    
550        return newLine;
551    }
552    
553  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
554      int i;      int i;
555    
# Line 414  static int lineWrite(FILE * out, struct Line 575  static int lineWrite(FILE * out, struct
575      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
576    
577   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
578   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
579        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
580      }      }
581    
582      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 595  static int getNextLine(char ** bufPtr, s
595      char * chptr;      char * chptr;
596      int elementsAlloced = 0;      int elementsAlloced = 0;
597      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
598      int first = 1;      int first = 1;
     int i;  
599    
600      lineFree(line);      lineFree(line);
601    
# Line 489  static int getNextLine(char ** bufPtr, s Line 649  static int getNextLine(char ** bufPtr, s
649      if (!line->numElements)      if (!line->numElements)
650   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
651      else {      else {
652   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
653      if (!strcmp(line->elements[0].item, keywords[i].key)) break;   if (line->type == LT_UNKNOWN) {
   
  if (keywords[i].key) {  
     line->type = keywords[i].type;  
  } else {  
     line->type = LT_UNKNOWN;  
               
654              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
655               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
656              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 686  static int getNextLine(char ** bufPtr, s
686   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
687   line->numElements = 0;   line->numElements = 0;
688      }      }
689     } else {
690     struct keywordTypes *kw;
691    
692     kw = getKeywordByType(line->type, cfi);
693    
694     /* space isn't the only separator, we need to split
695     * elements up more
696     */
697     if (!isspace(kw->separatorChar)) {
698        int i;
699        char indent[2] = "";
700        indent[0] = kw->separatorChar;
701        for (i = 1; i < line->numElements; i++) {
702     char *p;
703     int j;
704     int numNewElements;
705    
706     numNewElements = 0;
707     p = line->elements[i].item;
708     while (*p != '\0') {
709     if (*p == kw->separatorChar)
710     numNewElements++;
711     p++;
712     }
713     if (line->numElements + numNewElements >= elementsAlloced) {
714     elementsAlloced += numNewElements + 5;
715     line->elements = realloc(line->elements,
716        sizeof(*line->elements) * elementsAlloced);
717     }
718    
719     for (j = line->numElements; j > i; j--) {
720     line->elements[j + numNewElements] = line->elements[j];
721     }
722     line->numElements += numNewElements;
723    
724     p = line->elements[i].item;
725     while (*p != '\0') {
726    
727     while (*p != kw->separatorChar && *p != '\0') p++;
728     if (*p == '\0') {
729     break;
730     }
731    
732     free(line->elements[i].indent);
733     line->elements[i].indent = strdup(indent);
734     *p++ = '\0';
735     i++;
736     line->elements[i].item = strdup(p);
737     line->elements[i].indent = strdup("");
738     p = line->elements[i].item;
739     }
740        }
741     }
742   }   }
743      }      }
744    
# Line 614  static struct grubConfig * readConfig(co Line 821  static struct grubConfig * readConfig(co
821   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_DEFAULT && line->numElements == 2) {
822      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
823      defaultLine = line;      defaultLine = line;
824    
825            } else if (line->type == LT_KERNEL) {
826        /* if by some freak chance this is multiboot and the "module"
827         * lines came earlier in the template, make sure to use LT_HYPER
828         * instead of LT_KERNEL now
829         */
830        if (entry->multiboot)
831     line->type = LT_HYPER;
832    
833          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
834        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
835         * instead, now that we know this is a multiboot entry.
836         * This only applies to grub, but that's the only place we
837         * should find LT_MBMODULE lines anyway.
838         */
839        struct singleLine * l;
840        for (l = entry->lines; l; l = l->next) {
841     if (l->type == LT_HYPER)
842        break;
843     else if (l->type == LT_KERNEL) {
844        l->type = LT_HYPER;
845        break;
846     }
847        }
848              entry->multiboot = 1;              entry->multiboot = 1;
849    
850     } else if (line->type == LT_HYPER) {
851        entry->multiboot = 1;
852    
853   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
854      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
855      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
856    
857   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
858      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
859      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 878  static struct grubConfig * readConfig(co
878      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
879      line->elements[1].item = buf;      line->elements[1].item = buf;
880      line->numElements = 2;      line->numElements = 2;
881    
882   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
883      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
884         on write. This is one of the few (the only?) places that grubby         on write. This is one of the few (the only?) places that grubby
# Line 652  static struct grubConfig * readConfig(co Line 888  static struct grubConfig * readConfig(co
888   int last, len;   int last, len;
889    
890   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
891      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
892     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
893    
894   last = line->numElements - 1;   last = line->numElements - 1;
895   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
896   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
897      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
898      }      }
   
899   }   }
900    
901   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
# Line 680  static struct grubConfig * readConfig(co Line 915  static struct grubConfig * readConfig(co
915   movedLine = 1;   movedLine = 1;
916   continue; /* without setting 'last' */   continue; /* without setting 'last' */
917   }   }
918    
919   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
920     which was moved, drop it. */     which was moved, drop it. */
921   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {
# Line 695  static struct grubConfig * readConfig(co Line 931  static struct grubConfig * readConfig(co
931   entry->lines = line;   entry->lines = line;
932      else      else
933   last->next = line;   last->next = line;
934        dbgPrintf("readConfig added %d to %p\n", line->type, entry);
935   } else {   } else {
936      if (!cfg->theLines)      if (!cfg->theLines)
937   cfg->theLines = line;   cfg->theLines = line;
938      else {      else
939   last->next = line;   last->next = line;
940      }      dbgPrintf("readConfig added %d to cfg\n", line->type);
941   }   }
942    
943   last = line;   last = line;
# Line 730  static struct grubConfig * readConfig(co Line 967  static struct grubConfig * readConfig(co
967                                  extractTitle(line))) break;                                  extractTitle(line))) break;
968                  }                  }
969   i++;   i++;
970     entry = NULL;
971      }      }
972    
973      if (entry) cfg->defaultImage = i;      if (entry){
974            cfg->defaultImage = i;
975        }else{
976            cfg->defaultImage = -1;
977        }
978   }   }
979        } else {
980            cfg->defaultImage = 0;
981      }      }
982    
983      return cfg;      return cfg;
# Line 769  static void writeDefault(FILE * out, cha Line 1013  static void writeDefault(FILE * out, cha
1013    
1014      if (!entry) return;      if (!entry) return;
1015    
1016      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1017    
1018      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1019   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1047  static int writeConfig(struct grubConfig
1047      int rc;      int rc;
1048    
1049      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1050         directory to / */         directory to the dir of the symlink */
1051      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1052      do {      do {
1053   buf = alloca(len + 1);   buf = alloca(len + 1);
1054   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1055   if (rc == len) len += 256;   if (rc == len) len += 256;
1056      } while (rc == len);      } while (rc == len);
1057            
# Line 919  int suitableImage(struct singleEntry * e Line 1162  int suitableImage(struct singleEntry * e
1162      int i;      int i;
1163      struct stat sb, sb2;      struct stat sb, sb2;
1164      char * dev;      char * dev;
     char * end;  
1165      char * rootspec;      char * rootspec;
1166    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
       
     if (!line) return 0;  
1167      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) return 0;
1168      if (line->numElements < 2) return 0;  
1169        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1170        if (!line || line->numElements < 2) return 0;
1171    
1172      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1173    
# Line 935  int suitableImage(struct singleEntry * e Line 1175  int suitableImage(struct singleEntry * e
1175        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1176      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1177      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1178              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
                                       strlen(rootspec) : 0));  
1179      if (access(fullName, R_OK)) return 0;      if (access(fullName, R_OK)) return 0;
1180    
1181      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 945  int suitableImage(struct singleEntry * e Line 1184  int suitableImage(struct singleEntry * e
1184   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1185      } else {      } else {
1186   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1187   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1188    
1189   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1190      dev = line->elements[1].item;      dev = line->elements[1].item;
1191   } else {   } else {
1192              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1193      /* 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.
1194      line = entry->lines;       */
1195        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1196    
1197              /* failed to find one */              /* failed to find one */
1198              if (!line) return 0;              if (!line) return 0;
# Line 973  int suitableImage(struct singleEntry * e Line 1208  int suitableImage(struct singleEntry * e
1208   }   }
1209      }      }
1210    
1211      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1212   dev += 6;      if (!dev)
1213            return 0;
1214   /* check which device has this label */  
1215   dev = get_spec_by_volume_label(dev, &i, &i);      i = stat(dev, &sb);
1216   if (!dev) return 0;      if (i)
1217      }   return 0;
1218    
     if (*dev == '/') {  
  if (stat(dev, &sb))  
     return 0;  
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
     }  
1219      stat("/", &sb2);      stat("/", &sb2);
1220    
1221      if (sb.st_rdev != sb2.st_dev) return 0;      if (sb.st_rdev != sb2.st_dev)
1222            return 0;
1223    
1224      return 1;      return 1;
1225  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1263  struct singleEntry * findEntryByPath(str
1263   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1264   if (!entry) return NULL;   if (!entry) return NULL;
1265    
1266   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1267   if (!line) return NULL;   if (!line) return NULL;
1268    
1269   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1305  struct singleEntry * findEntryByPath(str
1305      kernel += 6;      kernel += 6;
1306   }   }
1307    
1308   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1309      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1310    
1311        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1312    
1313      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1314                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1315          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1316                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1317                              kernel + strlen(prefix)))       checkType, line);
1318                      break;   if (!line) break;  /* not found in this entry */
1319              }  
1320                 if (line && line->numElements >= 2) {
1321              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1322              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1323                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1324                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1325                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1326                      if (!strcmp(line->elements[1].item  +   }
1327                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1328    
1329      i++;      /* make sure this entry has a kernel identifier; this skips
1330         * non-Linux boot entries (could find netbsd etc, though, which is
1331         * unfortunate)
1332         */
1333        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1334     break; /* found 'im! */
1335   }   }
1336    
1337   if (index) *index = i;   if (index) *index = i;
1338      }      }
1339    
     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);  
     }  
   
1340      return entry;      return entry;
1341  }  }
1342    
# Line 1286  void displayEntry(struct singleEntry * e Line 1501  void displayEntry(struct singleEntry * e
1501      char * root = NULL;      char * root = NULL;
1502      int i;      int i;
1503    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1504      printf("index=%d\n", index);      printf("index=%d\n", index);
1505    
1506        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1507        if (!line) {
1508            printf("non linux entry\n");
1509            return;
1510        }
1511    
1512      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1513    
1514      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1526  void displayEntry(struct singleEntry * e
1526   }   }
1527   printf("\"\n");   printf("\"\n");
1528      } else {      } else {
1529   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1530   if (line) {   if (line) {
1531      char * s;      char * s;
1532    
# Line 1334  void displayEntry(struct singleEntry * e Line 1550  void displayEntry(struct singleEntry * e
1550      }      }
1551    
1552      if (!root) {      if (!root) {
1553   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1554   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1555      root=line->elements[1].item;      root=line->elements[1].item;
1556      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1565  void displayEntry(struct singleEntry * e
1565   printf("root=%s\n", s);   printf("root=%s\n", s);
1566      }      }
1567    
1568      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1569    
1570      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1571   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1436  int displayInfo(struct grubConfig * conf Line 1649  int displayInfo(struct grubConfig * conf
1649      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1650   dumpSysconfigGrub();   dumpSysconfigGrub();
1651      } else {      } else {
1652   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1653   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1654      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1655   }   }
1656    
1657   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1658   if (line) printf("lba\n");   if (line) printf("lba\n");
1659      }      }
1660    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1669  int displayInfo(struct grubConfig * conf
1669      return 0;      return 0;
1670  }  }
1671    
1672    struct singleLine * addLineTmpl(struct singleEntry * entry,
1673     struct singleLine * tmplLine,
1674     struct singleLine * prevLine,
1675     const char * val,
1676     struct configFileInfo * cfi)
1677    {
1678        struct singleLine * newLine = lineDup(tmplLine);
1679    
1680        if (val) {
1681     /* override the inherited value with our own.
1682     * This is a little weak because it only applies to elements[1]
1683     */
1684     if (newLine->numElements > 1)
1685        removeElement(newLine, 1);
1686     insertElement(newLine, val, 1, cfi);
1687    
1688     /* but try to keep the rootspec from the template... sigh */
1689     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1690        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1691        if (rootspec != NULL) {
1692     free(newLine->elements[1].item);
1693     newLine->elements[1].item =
1694        sdupprintf("%s%s", rootspec, val);
1695        }
1696     }
1697        }
1698    
1699        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1700          newLine->elements[0].item : "");
1701    
1702        if (!entry->lines) {
1703     /* first one on the list */
1704     entry->lines = newLine;
1705        } else if (prevLine) {
1706     /* add after prevLine */
1707     newLine->next = prevLine->next;
1708     prevLine->next = newLine;
1709        }
1710    
1711        return newLine;
1712    }
1713    
1714  /* val may be NULL */  /* val may be NULL */
1715  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1716       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1717       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1718       char * val) {       const char * val) {
1719      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1720      int i;      struct keywordTypes * kw;
1721        struct singleLine tmpl;
1722    
1723      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1724   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1725      if (type != LT_TITLE || !cfi->titleBracketed)       */
1726          if (!cfi->keywords[i].key) abort();  
1727        if (type == LT_TITLE && cfi->titleBracketed) {
1728     /* we're doing a bracketed title (zipl) */
1729     tmpl.type = type;
1730     tmpl.numElements = 1;
1731     tmpl.elements = alloca(sizeof(*tmpl.elements));
1732     tmpl.elements[0].item = alloca(strlen(val)+3);
1733     sprintf(tmpl.elements[0].item, "[%s]", val);
1734     tmpl.elements[0].indent = "";
1735     val = NULL;
1736        } else {
1737     kw = getKeywordByType(type, cfi);
1738     if (!kw) abort();
1739     tmpl.type = type;
1740     tmpl.numElements = val ? 2 : 1;
1741     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1742     tmpl.elements[0].item = kw->key;
1743     tmpl.elements[0].indent = alloca(2);
1744     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1745     if (val) {
1746        tmpl.elements[1].item = (char *)val;
1747        tmpl.elements[1].indent = "";
1748     }
1749        }
1750    
1751      /* The last non-empty line gives us the indention to us and the line      /* The last non-empty line gives us the indention to us and the line
1752         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1753         may not be ideal? If there are no lines or we are looking at the         may not be ideal? If there are no lines or we are looking at the
1754         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1755         differently from the rest) */         differently from the rest) */
1756      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1757   line = entry->lines;   if (line->numElements) prev = line;
1758   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1759   while (line) {   if (!line->next && !prev) prev = 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;  
1760      }      }
1761    
1762      if (type != LT_TITLE || !cfi->titleBracketed) {      if (prev == entry->lines)
1763          line->type = type;   tmpl.indent = defaultIndent ?: "";
1764          line->numElements = val ? 2 : 1;      else
1765          line->elements = malloc(sizeof(*line->elements) * line->numElements);   tmpl.indent = prev->indent;
         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("");  
     }  
1766    
1767      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1768  }  }
1769    
1770  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 1789  void removeLine(struct singleEntry * ent
1789      free(line);      free(line);
1790  }  }
1791    
1792    static void insertElement(struct singleLine * line,
1793      const char * item, int insertHere,
1794      struct configFileInfo * cfi)
1795    {
1796        struct keywordTypes * kw;
1797        char indent[2] = "";
1798    
1799        /* sanity check */
1800        if (insertHere > line->numElements) {
1801     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
1802      insertHere, line->numElements);
1803     insertHere = line->numElements;
1804        }
1805    
1806        line->elements = realloc(line->elements, (line->numElements + 1) *
1807         sizeof(*line->elements));
1808        memmove(&line->elements[insertHere+1],
1809        &line->elements[insertHere],
1810        (line->numElements - insertHere) *
1811        sizeof(*line->elements));
1812        line->elements[insertHere].item = strdup(item);
1813    
1814        kw = getKeywordByType(line->type, cfi);
1815    
1816        if (line->numElements == 0) {
1817     indent[0] = '\0';
1818        } else if (insertHere == 0) {
1819     indent[0] = kw->nextChar;
1820        } else if (kw->separatorChar != '\0') {
1821     indent[0] = kw->separatorChar;
1822        } else {
1823     indent[0] = ' ';
1824        }
1825    
1826        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
1827     /* move the end-of-line forward */
1828     line->elements[insertHere].indent =
1829        line->elements[insertHere-1].indent;
1830     line->elements[insertHere-1].indent = strdup(indent);
1831        } else {
1832     line->elements[insertHere].indent = strdup(indent);
1833        }
1834    
1835        line->numElements++;
1836    
1837        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
1838          line->elements[0].item,
1839          line->elements[insertHere].item,
1840          line->elements[insertHere].indent,
1841          insertHere);
1842    }
1843    
1844    static void removeElement(struct singleLine * line, int removeHere) {
1845        int i;
1846    
1847        /* sanity check */
1848        if (removeHere >= line->numElements) return;
1849    
1850        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
1851          removeHere, line->elements[removeHere].item);
1852    
1853        free(line->elements[removeHere].item);
1854    
1855        if (removeHere > 1) {
1856     /* previous argument gets this argument's post-indentation */
1857     free(line->elements[removeHere-1].indent);
1858     line->elements[removeHere-1].indent =
1859        line->elements[removeHere].indent;
1860        } else {
1861     free(line->elements[removeHere].indent);
1862        }
1863    
1864        /* now collapse the array, but don't bother to realloc smaller */
1865        for (i = removeHere; i < line->numElements - 1; i++)
1866     line->elements[i] = line->elements[i + 1];
1867    
1868        line->numElements--;
1869    }
1870    
1871  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
1872      char * first, * second;      char * first, * second;
1873      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 1890  int updateActualImage(struct grubConfig
1890      struct singleEntry * entry;      struct singleEntry * entry;
1891      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
1892      int index = 0;      int index = 0;
1893      int i, j, k;      int i, k;
1894      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
1895      const char ** arg;      const char ** arg;
1896      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
1897      int firstElement;      int firstElement;
1898      int *usedElements, *usedArgs;      int *usedElements, *usedArgs;
1899        int doreplace;
1900    
1901      if (!image) return 0;      if (!image) return 0;
1902    
# Line 1609  int updateActualImage(struct grubConfig Line 1923  int updateActualImage(struct grubConfig
1923   }   }
1924      }      }
1925    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
1926    
1927      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
1928   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
1929    
1930      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
1931   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
1932    
1933      if (cfg->cfi->keywords[i].key)      for (k = 0, arg = newArgs; *arg; arg++, k++) ;
1934   useRoot = 1;      usedArgs = calloc(k, sizeof(*usedArgs));
1935    
1936      k = 0;      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
1937      for (arg = newArgs; *arg; arg++)  
1938          k++;   if (multibootArgs && !entry->multiboot)
1939      usedArgs = calloc(k, sizeof(int));      continue;
1940    
1941     /* Determine where to put the args.  If this config supports
1942     * LT_KERNELARGS, use that.  Otherwise use
1943     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
1944     */
1945     if (useKernelArgs) {
1946        line = getLineByType(LT_KERNELARGS, entry->lines);
1947        if (!line) {
1948     /* no LT_KERNELARGS, need to add it */
1949     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
1950           cfg->secondaryIndent, NULL);
1951        }
1952        firstElement = 1;
1953    
1954      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
1955   index++;      line = getLineByType(LT_HYPER, entry->lines);
1956        if (!line) {
1957     /* a multiboot entry without LT_HYPER? */
1958     continue;
1959        }
1960        firstElement = 2;
1961    
1962   line = entry->lines;   } else {
1963   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
1964   if (!line) continue;      if (!line) {
1965   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
1966     continue;
1967          if (entry->multiboot && !multibootArgs) {      }
1968              /* first mb module line is the real kernel */      firstElement = 2;
             while (line && line->type != LT_MBMODULE) line = line->next;  
             firstElement = 2;  
         } else if (useKernelArgs) {  
     while (line && line->type != LT_KERNELARGS) line = line->next;  
     firstElement = 1;  
1969   }   }
1970    
1971   if (!line && useKernelArgs) {   /* handle the elilo case which does:
1972      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
1973      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
1974     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
1975        /* this is a multiboot entry, make sure there's
1976         * -- on the args line
1977         */
1978        for (i = firstElement; i < line->numElements; i++) {
1979     if (!strcmp(line->elements[i].item, "--"))
1980        break;
1981        }
1982        if (i == line->numElements) {
1983     /* assume all existing args are kernel args,
1984     * prepend -- to make it official
1985     */
1986     insertElement(line, "--", firstElement, cfg->cfi);
1987     i = firstElement;
1988        }
1989        if (!multibootArgs) {
1990     /* kernel args start after the -- */
1991     firstElement = i + 1;
1992        }
1993     } else if (cfg->cfi->mbConcatArgs) {
1994        /* this is a non-multiboot entry, remove hyper args */
1995        for (i = firstElement; i < line->numElements; i++) {
1996     if (!strcmp(line->elements[i].item, "--"))
1997        break;
1998        }
1999        if (i < line->numElements) {
2000     /* remove args up to -- */
2001     while (strcmp(line->elements[firstElement].item, "--"))
2002        removeElement(line, firstElement);
2003     /* remove -- */
2004     removeElement(line, firstElement);
2005        }
2006   }   }
2007    
2008          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2009    
2010          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2011   for (arg = newArgs; *arg; arg++) {              if (usedArgs[k]) continue;
2012              if (usedArgs[k]) {  
2013                  k++;      doreplace = 1;
                 continue;  
             }  
2014      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2015     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2016        !strcmp(line->elements[i].item, "--"))
2017     {
2018        /* reached the end of hyper args, insert here */
2019        doreplace = 0;
2020        break;  
2021     }
2022                  if (usedElements[i])                  if (usedElements[i])
2023                      continue;                      continue;
2024   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
# Line 1665  int updateActualImage(struct grubConfig Line 2027  int updateActualImage(struct grubConfig
2027      break;      break;
2028                  }                  }
2029              }              }
     chptr = strchr(*arg, '=');  
2030    
2031      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2032   /* replace */   /* direct replacement */
2033   free(line->elements[i].item);   free(line->elements[i].item);
2034   line->elements[i].item = strdup(*arg);   line->elements[i].item = strdup(*arg);
     } else if (useRoot && !strncmp(*arg, "root=/dev/", 10) && *chptr) {  
  rootLine = entry->lines;  
  while (rootLine && rootLine->type != LT_ROOT)  
     rootLine = rootLine->next;  
  if (!rootLine) {  
     rootLine = addLine(entry, cfg->cfi, LT_ROOT, NULL, NULL);  
     rootLine->elements = realloc(rootLine->elements,  
     2 * sizeof(*rootLine->elements));  
     rootLine->numElements++;  
     rootLine->elements[1].indent = strdup("");  
     rootLine->elements[1].item = strdup("");  
  }  
2035    
2036   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2037   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2038      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2039   /* append */   if (rootLine) {
2040   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2041   (line->numElements + 1) * sizeof(*line->elements));      rootLine->elements[1].item = strdup(*arg + 5);
  line->elements[line->numElements].item = strdup(*arg);  
  usedElements = realloc(usedElements,  
  (line->numElements + 1) * sizeof(int));  
  usedElements[line->numElements] = 1;  
   
  if (line->numElements > 1) {  
     /* add to existing list of arguments */  
     line->elements[line->numElements].indent =  
  line->elements[line->numElements - 1].indent;  
     line->elements[line->numElements - 1].indent = strdup(" ");  
2042   } else {   } else {
2043      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2044         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2045   }   }
2046        }
2047    
2048   line->numElements++;      else {
2049     /* insert/append */
2050     insertElement(line, *arg, i, cfg->cfi);
2051     usedElements = realloc(usedElements, line->numElements *
2052           sizeof(*usedElements));
2053     memmove(&usedElements[i + 1], &usedElements[i],
2054     line->numElements - i - 1);
2055     usedElements[i] = 1;
2056    
2057   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2058     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2059     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2060   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2061      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2062      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2063   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2064   }   }
2065      }      }
             k++;  
2066   }   }
2067    
2068          free(usedElements);          free(usedElements);
2069    
  /* no arguments to remove (i.e. no append line) */  
  if (!line) continue;  
   
  /* this won't remove an LT_ROOT item properly (but then again,  
    who cares? */  
2070   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2071      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2072   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2073        !strcmp(line->elements[i].item, "--"))
2074        /* reached the end of hyper args, stop here */
2075        break;
2076     if (!argMatch(line->elements[i].item, *arg)) {
2077        removeElement(line, i);
2078      break;      break;
   
     if (i < line->numElements) {  
  /* if this isn't the first argument the previous argument  
    gets this arguments post-indention */  
  if (i > firstElement) {  
     free(line->elements[i - 1].indent);  
     line->elements[i - 1].indent = line->elements[i].indent;  
2079   }   }
2080        }
2081   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2082        if (useRoot && !strncmp(*arg, "root=", 5)) {
2083   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2084      line->elements[j - 1] = line->elements[j];   if (rootLine)
2085        removeLine(entry, rootLine);
  line->numElements--;  
2086      }      }
2087   }   }
2088    
# Line 1976  int checkForGrub(struct grubConfig * con Line 2309  int checkForGrub(struct grubConfig * con
2309      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2310   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2311   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2312     close(fd);
2313     return 1;
2314        }
2315        close(fd);
2316    
2317        return checkDeviceBootloader(boot, bootSect);
2318    }
2319    
2320    int checkForExtLinux(struct grubConfig * config) {
2321        int fd;
2322        unsigned char bootSect[512];
2323        char * boot;
2324        char executable[] = "/boot/extlinux/extlinux";
2325    
2326        printf("entered: checkForExtLinux()\n");
2327    
2328        if (parseSysconfigGrub(NULL, &boot))
2329     return 0;
2330    
2331        /* assume grub is not installed -- not an error condition */
2332        if (!boot)
2333     return 0;
2334    
2335        fd = open(executable, O_RDONLY);
2336        if (fd < 0)
2337     /* this doesn't exist if grub hasn't been installed */
2338     return 0;
2339    
2340        if (read(fd, bootSect, 512) != 512) {
2341     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2342     executable, strerror(errno));
2343   return 1;   return 1;
2344      }      }
2345      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2358  static char * getRootSpecifier(char * st
2358      return rootspec;      return rootspec;
2359  }  }
2360    
2361    static char * getInitrdVal(struct grubConfig * config,
2362       const char * prefix, struct singleLine *tmplLine,
2363       const char * newKernelInitrd,
2364       char ** extraInitrds, int extraInitrdCount)
2365    {
2366        char *initrdVal, *end;
2367        int i;
2368        size_t totalSize;
2369        size_t prefixLen;
2370        char separatorChar;
2371    
2372        prefixLen = strlen(prefix);
2373        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2374    
2375        for (i = 0; i < extraInitrdCount; i++) {
2376     totalSize += sizeof(separatorChar);
2377     totalSize += strlen(extraInitrds[i]) - prefixLen;
2378        }
2379    
2380        initrdVal = end = malloc(totalSize);
2381    
2382        end = stpcpy (end, newKernelInitrd + prefixLen);
2383    
2384        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2385        for (i = 0; i < extraInitrdCount; i++) {
2386     const char *extraInitrd;
2387     int j;
2388    
2389     extraInitrd = extraInitrds[i] + prefixLen;
2390     /* Don't add entries that are already there */
2391     if (tmplLine != NULL) {
2392        for (j = 2; j < tmplLine->numElements; j++)
2393     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2394        break;
2395    
2396        if (j != tmplLine->numElements)
2397     continue;
2398     }
2399    
2400     *end++ = separatorChar;
2401     end = stpcpy(end, extraInitrd);
2402        }
2403    
2404        return initrdVal;
2405    }
2406    
2407  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2408           const char * prefix,           const char * prefix,
2409   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2410   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2411     char ** extraInitrds, int extraInitrdCount,
2412                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2413      struct singleEntry * new;      struct singleEntry * new;
2414      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2415      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2416      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2417    
2418      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2419    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2443  int addNewKernel(struct grubConfig * con
2443      config->entries = new;      config->entries = new;
2444    
2445      /* copy/update from the template */      /* copy/update from the template */
2446      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2447        if (newKernelInitrd)
2448     needs |= NEED_INITRD;
2449      if (newMBKernel) {      if (newMBKernel) {
2450          needs |= KERNEL_MB;          needs |= NEED_MB;
2451          new->multiboot = 1;          new->multiboot = 1;
2452      }      }
2453    
2454      if (template) {      if (template) {
2455   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2456      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2457      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2458   indent = tmplLine->indent;   {
2459        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2460    
2461      /* skip comments */      /* skip comments */
2462      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2463      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2464      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2465    
2466      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2467      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   tmplLine->numElements >= 2) {
2468     if (!template->multiboot && (needs & NEED_MB)) {
2469              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2470                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2471                  struct singleLine *l;       * hypervisor at the same time.
2472                  needs &= ~ KERNEL_MB;       */
2473        if (config->cfi->mbHyperFirst) {
2474                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2475                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2476                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2477                      newMBKernel + strlen(prefix));
2478                  tmplLine = lastLine;   /* set up for adding the kernel line */
2479                  if (!new->lines) {   free(tmplLine->indent);
2480                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2481                  } else {   needs &= ~NEED_MB;
2482                      newLine->next = l;      }
2483                      newLine = l;      if (needs & NEED_KERNEL) {
2484                  }   /* use addLineTmpl to preserve line elements,
2485                  continue;   * otherwise we could just call addLine.  Unfortunately
2486              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2487                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2488                  continue; /* don't need multiboot kernel here */   * change below.
2489              }   */
2490     struct keywordTypes * mbm_kw =
2491        getKeywordByType(LT_MBMODULE, config->cfi);
2492     if (mbm_kw) {
2493        tmplLine->type = LT_MBMODULE;
2494        free(tmplLine->elements[0].item);
2495        tmplLine->elements[0].item = strdup(mbm_kw->key);
2496     }
2497     newLine = addLineTmpl(new, tmplLine, newLine,
2498          newKernelPath + strlen(prefix), config->cfi);
2499     needs &= ~NEED_KERNEL;
2500        }
2501        if (needs & NEED_MB) { /* !mbHyperFirst */
2502     newLine = addLine(new, config->cfi, LT_HYPER,
2503      config->secondaryIndent,
2504      newMBKernel + strlen(prefix));
2505     needs &= ~NEED_MB;
2506        }
2507     } else if (needs & NEED_KERNEL) {
2508        newLine = addLineTmpl(new, tmplLine, newLine,
2509      newKernelPath + strlen(prefix), config->cfi);
2510        needs &= ~NEED_KERNEL;
2511     }
2512    
2513      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2514   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2515   new->lines = newLine;   if (needs & NEED_MB) {
2516      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2517   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2518   newLine = newLine->next;      needs &= ~NEED_MB;
2519      }   }
2520    
2521        } else if (tmplLine->type == LT_MBMODULE &&
2522           tmplLine->numElements >= 2) {
2523     if (new->multiboot) {
2524        if (needs & NEED_KERNEL) {
2525     newLine = addLineTmpl(new, tmplLine, newLine,
2526          newKernelPath +
2527          strlen(prefix), config->cfi);
2528     needs &= ~NEED_KERNEL;
2529        } else if (config->cfi->mbInitRdIsModule &&
2530           (needs & NEED_INITRD)) {
2531     char *initrdVal;
2532     initrdVal = getInitrdVal(config, prefix, tmplLine,
2533     newKernelInitrd, extraInitrds,
2534     extraInitrdCount);
2535     newLine = addLineTmpl(new, tmplLine, newLine,
2536          initrdVal, config->cfi);
2537     free(initrdVal);
2538     needs &= ~NEED_INITRD;
2539        }
2540     } else if (needs & NEED_KERNEL) {
2541        /* template is multi but new is not,
2542         * insert the kernel in the first module slot
2543         */
2544        tmplLine->type = LT_KERNEL;
2545        free(tmplLine->elements[0].item);
2546        tmplLine->elements[0].item =
2547     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2548        newLine = addLineTmpl(new, tmplLine, newLine,
2549      newKernelPath + strlen(prefix), config->cfi);
2550        needs &= ~NEED_KERNEL;
2551     } else if (needs & NEED_INITRD) {
2552        char *initrdVal;
2553        /* template is multi but new is not,
2554         * insert the initrd in the second module slot
2555         */
2556        tmplLine->type = LT_INITRD;
2557        free(tmplLine->elements[0].item);
2558        tmplLine->elements[0].item =
2559     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2560        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2561        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2562        free(initrdVal);
2563        needs &= ~NEED_INITRD;
2564     }
2565    
     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);  
     }  
   
             lastLine = tmplLine;  
     if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {  
                 char * repl;  
                 if (!template->multiboot) {  
                     needs &= ~KERNEL_KERNEL;  
                     repl = newKernelPath;  
                 } else {  
                     needs &= ~KERNEL_MB;  
                     repl = newMBKernel;  
                 }  
                 if (new->multiboot && !template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("module");  
                     newLine->type = LT_MBMODULE;  
                 }  
  free(newLine->elements[1].item);  
                 rootspec = getRootSpecifier(tmplLine->elements[1].item);  
                 if (rootspec != NULL) {  
                     newLine->elements[1].item = sdupprintf("%s%s",  
                                                            rootspec,  
                                                            repl +  
                                                            strlen(prefix));  
                 } else {  
                     newLine->elements[1].item = strdup(repl +  
                                                        strlen(prefix));  
                 }  
             } else if (tmplLine->type == LT_MBMODULE &&  
                        tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {  
                 needs &= ~KERNEL_KERNEL;  
                 if (!new->multiboot && template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("kernel");  
                     newLine->type = LT_KERNEL;  
                 }  
  free(newLine->elements[1].item);  
                 rootspec = getRootSpecifier(tmplLine->elements[1].item);  
                 if (rootspec != NULL) {  
                     newLine->elements[1].item = sdupprintf("%s%s",  
                                                            rootspec,  
                                                            newKernelPath +  
                                                            strlen(prefix));  
                 } else {  
                     newLine->elements[1].item = strdup(newKernelPath +  
                                                        strlen(prefix));  
                 }  
2566      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2567      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2568   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2569   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2570                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2571                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2572                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2573                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2574                  }       */
2575                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2576                  if (rootspec != NULL) {   char *initrdVal;
2577                      newLine->elements[1].item = sdupprintf("%s%s",  
2578                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2579                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2580                                                             strlen(prefix));    config->secondaryIndent,
2581                  } else {    initrdVal);
2582                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2583                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2584                  }      }
2585              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2586                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2587   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2588                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2589                      free(newLine->elements[0].item);      free(initrdVal);
2590                      newLine->elements[0].item = strdup("initrd");      needs &= ~NEED_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);  
2591   }   }
2592    
  newLine->elements[1].item = strdup(newKernelTitle);  
  newLine->elements[1].indent = strdup("");  
  newLine->numElements = 2;  
2593      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2594                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2595                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2596                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2597                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2598                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2599                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2600                                             newLine->numElements);     config->cfi->titleBracketed) {
2601        /* addLineTmpl doesn't handle titleBracketed */
2602                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2603                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2604                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2605                  newLine->numElements = 1;   }
2606              }  
2607        } else {
2608     /* pass through other lines from the template */
2609     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2610        }
2611   }   }
2612    
2613      } else {      } else {
2614   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2615      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2616     */
2617     switch (config->cfi->entrySeparator) {
2618        case LT_KERNEL:
2619     if (new->multiboot && config->cfi->mbHyperFirst) {
2620        /* fall through to LT_HYPER */
2621     } else {
2622        newLine = addLine(new, config->cfi, LT_KERNEL,
2623          config->primaryIndent,
2624          newKernelPath + strlen(prefix));
2625        needs &= ~NEED_KERNEL;
2626        break;
2627     }
2628    
2629        case LT_HYPER:
2630     newLine = addLine(new, config->cfi, LT_HYPER,
2631      config->primaryIndent,
2632      newMBKernel + strlen(prefix));
2633     needs &= ~NEED_MB;
2634   break;   break;
         }  
2635    
2636   switch (config->cfi->keywords[i].type) {      case LT_TITLE:
2637      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
2638       chptr = newKernelPath + strlen(prefix);   char * templabel;
2639       type = LT_KERNEL; break;   int x = 0, y = 0;
2640      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;  
2641       type = LT_TITLE; break;   templabel = strdup(newKernelTitle);
2642      default:       while( templabel[x]){
2643                  /* zipl strikes again */   if( templabel[x] == ' ' ){
2644                  if (config->cfi->titleBracketed) {   y = x;
2645                      needs &= ~KERNEL_TITLE;   while( templabel[y] ){
2646                      chptr = newKernelTitle;   templabel[y] = templabel[y+1];
2647                      type = LT_TITLE;   y++;
2648                      break;   }
2649                  } else {   }
2650                      abort();   x++;
2651                  }   }
2652   }   newLine = addLine(new, config->cfi, LT_TITLE,
2653      config->primaryIndent, templabel);
2654     free(templabel);
2655     }else{
2656     newLine = addLine(new, config->cfi, LT_TITLE,
2657      config->primaryIndent, newKernelTitle);
2658     }
2659     needs &= ~NEED_TITLE;
2660     break;
2661    
2662   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
2663   new->lines = newLine;   abort();
2664     }
2665      }      }
2666    
2667      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
2668          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
2669              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entrySeparator.
2670                                config->secondaryIndent,       */
2671                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
2672          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
2673              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
2674                                config->secondaryIndent,    newKernelTitle);
2675                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
2676          /* don't need to check for title as it's guaranteed to have been      }
2677           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
2678           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
2679          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
2680              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
2681                                config->secondaryIndent,   needs &= ~NEED_MB;
2682                                newKernelInitrd + strlen(prefix));      }
2683      } else {      if (needs & NEED_KERNEL) {
2684          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
2685              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
2686                                config->secondaryIndent,        config->cfi)) ?
2687                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
2688          if (needs & KERNEL_TITLE)    config->secondaryIndent,
2689              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
2690                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
2691                                newKernelTitle);      }
2692          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
2693              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
2694                                config->secondaryIndent,    config->secondaryIndent,
2695                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
2696     needs &= ~NEED_MB;
2697        }
2698        if (needs & NEED_INITRD) {
2699     char *initrdVal;
2700     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
2701     newLine = addLine(new, config->cfi,
2702      (new->multiboot && getKeywordByType(LT_MBMODULE,
2703          config->cfi)) ?
2704      LT_MBMODULE : LT_INITRD,
2705      config->secondaryIndent,
2706      initrdVal);
2707     free(initrdVal);
2708     needs &= ~NEED_INITRD;
2709        }
2710    
2711        if (needs) {
2712     printf(_("grubby: needs=%d, aborting\n"), needs);
2713     abort();
2714      }      }
2715    
2716      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 2719  int addNewKernel(struct grubConfig * con
2719      return 0;      return 0;
2720  }  }
2721    
2722    static void traceback(int signum)
2723    {
2724        void *array[40];
2725        size_t size;
2726    
2727        signal(SIGSEGV, SIG_DFL);
2728        memset(array, '\0', sizeof (array));
2729        size = backtrace(array, 40);
2730    
2731        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
2732                (unsigned long)size);
2733        backtrace_symbols_fd(array, size, STDERR_FILENO);
2734        exit(1);
2735    }
2736    
2737  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
2738      poptContext optCon;      poptContext optCon;
2739      char * grubConfig = NULL;      char * grubConfig = NULL;
# Line 2283  int main(int argc, const char ** argv) { Line 2743  int main(int argc, const char ** argv) {
2743      int badImageOkay = 0;      int badImageOkay = 0;
2744      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
2745      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
2746        int configureExtLinux = 0;
2747      int bootloaderProbe = 0;      int bootloaderProbe = 0;
2748        int extraInitrdCount = 0;
2749      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
2750      char * newKernelPath = NULL;      char * newKernelPath = NULL;
2751      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 2761  int main(int argc, const char ** argv) {
2761      char * defaultKernel = NULL;      char * defaultKernel = NULL;
2762      char * removeArgs = NULL;      char * removeArgs = NULL;
2763      char * kernelInfo = NULL;      char * kernelInfo = NULL;
2764        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
2765      const char * chptr = NULL;      const char * chptr = NULL;
2766      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
2767      struct grubConfig * config;      struct grubConfig * config;
# Line 2339  int main(int argc, const char ** argv) { Line 2802  int main(int argc, const char ** argv) {
2802      _("display the path of the default kernel") },      _("display the path of the default kernel") },
2803   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
2804      _("configure elilo bootloader") },      _("configure elilo bootloader") },
2805     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
2806        _("configure extlinux bootloader (from syslinux)") },
2807   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
2808      _("configure grub bootloader") },      _("configure grub bootloader") },
2809   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
# Line 2346  int main(int argc, const char ** argv) { Line 2811  int main(int argc, const char ** argv) {
2811      _("kernel-path") },      _("kernel-path") },
2812   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
2813      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
2814     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
2815        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
2816   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
2817      _("configure lilo bootloader") },      _("configure lilo bootloader") },
2818   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 2849  int main(int argc, const char ** argv) {
2849   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
2850      };      };
2851    
2852        useextlinuxmenu=0;
2853    
2854        signal(SIGSEGV, traceback);
2855    
2856      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
2857      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
2858    
# Line 2391  int main(int argc, const char ** argv) { Line 2862  int main(int argc, const char ** argv) {
2862      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
2863      exit(0);      exit(0);
2864      break;      break;
2865      case 'i':
2866        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
2867         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
2868        } else {
2869     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
2870     return 1;
2871        }
2872        break;
2873   }   }
2874      }      }
2875    
# Line 2407  int main(int argc, const char ** argv) { Line 2886  int main(int argc, const char ** argv) {
2886      }      }
2887    
2888      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub + configureELilo +
2889   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
2890     configureExtLinux ) > 1) {
2891   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
2892   return 1;   return 1;
2893      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
# Line 2426  int main(int argc, const char ** argv) { Line 2906  int main(int argc, const char ** argv) {
2906          cfi = &siloConfigType;          cfi = &siloConfigType;
2907      } else if (configureZipl) {      } else if (configureZipl) {
2908          cfi = &ziplConfigType;          cfi = &ziplConfigType;
2909        } else if (configureExtLinux) {
2910     cfi = &extlinuxConfigType;
2911     useextlinuxmenu=1;
2912      }      }
2913    
2914      if (!cfi) {      if (!cfi) {
# Line 2467  int main(int argc, const char ** argv) { Line 2950  int main(int argc, const char ** argv) {
2950   return 1;   return 1;
2951      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||
2952    newKernelInitrd || copyDefault     ||    newKernelInitrd || copyDefault     ||
2953    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
2954   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
2955   return 1;   return 1;
2956      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3003  int main(int argc, const char ** argv) {
3003   bootPrefix = "";   bootPrefix = "";
3004      }      }
3005    
3006        if (!cfi->mbAllowExtraInitRds &&
3007     extraInitrdCount > 0) {
3008     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3009     return 1;
3010        }
3011    
3012      if (bootloaderProbe) {      if (bootloaderProbe) {
3013   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, erc = 0;
3014   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3015    
3016   if (!access(grubConfigType.defaultConfig, F_OK)) {   if (!access(grubConfigType.defaultConfig, F_OK)) {
# Line 2540  int main(int argc, const char ** argv) { Line 3029  int main(int argc, const char ** argv) {
3029   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3030   }   }
3031    
3032     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3033        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3034        if (!lconfig)
3035     erc = 1;
3036        else
3037     erc = checkForExtLinux(lconfig);
3038     }
3039    
3040   if (lrc == 1 || grc == 1) return 1;   if (lrc == 1 || grc == 1) return 1;
3041    
3042   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3043   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3044     if (erc == 2) printf("extlinux\n");
3045    
3046   return 0;   return 0;
3047      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3059  int main(int argc, const char ** argv) {
3059   if (!entry) return 0;   if (!entry) return 0;
3060   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3061    
3062   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3063   if (!line) return 0;   if (!line) return 0;
3064    
3065          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2587  int main(int argc, const char ** argv) { Line 3084  int main(int argc, const char ** argv) {
3084                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3085      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3086                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3087                         extraInitrds, extraInitrdCount,
3088                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3089            
3090    

Legend:
Removed from v.532  
changed lines
  Added in v.914