Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1694 by niro, Fri Feb 17 23:23:07 2012 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    #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43  #include "mount_by_label.h"  #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49  #define _(A) (A)  #define _(A) (A)
50    
51    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
52  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
53    
54  /* comments get lumped in with indention */  /* comments get lumped in with indention */
# Line 38  struct lineElement { Line 57  struct lineElement {
57      char * indent;      char * indent;
58  };  };
59    
60  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
61         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE = 1 << 0,
62         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE      = 1 << 1,
63        LT_KERNEL     = 1 << 2,
64        LT_INITRD     = 1 << 3,
65        LT_HYPER      = 1 << 4,
66        LT_DEFAULT    = 1 << 5,
67        LT_MBMODULE   = 1 << 6,
68        LT_ROOT       = 1 << 7,
69        LT_FALLBACK   = 1 << 8,
70        LT_KERNELARGS = 1 << 9,
71        LT_BOOT       = 1 << 10,
72        LT_BOOTROOT   = 1 << 11,
73        LT_LBA        = 1 << 12,
74        LT_OTHER      = 1 << 13,
75        LT_GENERIC    = 1 << 14,
76        LT_UNKNOWN    = 1 << 15,
77    };
78    
79  struct singleLine {  struct singleLine {
80      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 95  struct singleEntry {
95    
96  #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 */
97    
98  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
99  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
100  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
101  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
102  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
103    #define NEED_MB      (1 << 4)
104    
105  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
106  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 74  struct keywordTypes { Line 109  struct keywordTypes {
109      char * key;      char * key;
110      enum lineType_e type;      enum lineType_e type;
111      char nextChar;      char nextChar;
112  } ;      char separatorChar;
113    };
114    
115  struct configFileInfo {  struct configFileInfo {
116      char * defaultConfig;      char * defaultConfig;
117      struct keywordTypes * keywords;      struct keywordTypes * keywords;
118      int defaultIsIndex;      int defaultIsIndex;
119      int defaultSupportSaved;      int defaultSupportSaved;
120      enum lineType_e entrySeparator;      enum lineType_e entryStart;
121      int needsBootPrefix;      int needsBootPrefix;
122      int argsInQuotes;      int argsInQuotes;
123      int maxTitleLength;      int maxTitleLength;
124      int titleBracketed;      int titleBracketed;
125        int mbHyperFirst;
126        int mbInitRdIsModule;
127        int mbConcatArgs;
128        int mbAllowExtraInitRds;
129  };  };
130    
131  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 134  struct keywordTypes grubKeywords[] = {
134      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
135      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
136      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
137      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
138      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
139        { "kernel",     LT_HYPER,       ' ' },
140      { NULL,    0, 0 },      { NULL,    0, 0 },
141  };  };
142    
143  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
144      "/boot/grub/grub.conf",    /* defaultConfig */      .defaultConfig = "/boot/grub/grub.conf",
145      grubKeywords,    /* keywords */      .keywords = grubKeywords,
146      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
147      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
148      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
149      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
150      0,    /* argsInQuotes */      .mbHyperFirst = 1,
151      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
152      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
153  };  };
154    
155  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 183  struct keywordTypes yabootKeywords[] = {
183      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
184      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
185      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
186      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
187      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
188      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
189      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 203  struct keywordTypes liloKeywords[] = {
203      { NULL,    0, 0 },      { NULL,    0, 0 },
204  };  };
205    
206    struct keywordTypes eliloKeywords[] = {
207        { "label",    LT_TITLE,    '=' },
208        { "root",    LT_ROOT,    '=' },
209        { "default",    LT_DEFAULT,    '=' },
210        { "image",    LT_KERNEL,    '=' },
211        { "initrd",    LT_INITRD,    '=' },
212        { "append",    LT_KERNELARGS,  '=' },
213        { "vmm",    LT_HYPER,       '=' },
214        { NULL,    0, 0 },
215    };
216    
217  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
218      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
219      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 235  struct keywordTypes ziplKeywords[] = {
235      { NULL,         0, 0 },      { NULL,         0, 0 },
236  };  };
237    
238    struct keywordTypes extlinuxKeywords[] = {
239        { "label",    LT_TITLE,    ' ' },
240        { "root",    LT_ROOT,    ' ' },
241        { "default",    LT_DEFAULT,    ' ' },
242        { "kernel",    LT_KERNEL,    ' ' },
243        { "initrd",    LT_INITRD,      ' ', ',' },
244        { "append",    LT_KERNELARGS,  ' ' },
245        { "prompt",     LT_UNKNOWN,     ' ' },
246        { NULL,    0, 0 },
247    };
248    int useextlinuxmenu;
249  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
250      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
251      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
252      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
253      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
254      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
255      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
256  };  };
257    
258  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
259      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
260      liloKeywords,    /* keywords */      .keywords = liloKeywords,
261      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
262      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
263      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
264  };  };
265    
266  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
267      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
268      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
269      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
270      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
271      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
272      1,    /* needsBootPrefix */      .maxTitleLength = 15,
273      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
274  };  };
275    
276  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
277      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
278      siloKeywords,    /* keywords */      .keywords = siloKeywords,
279      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
280      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
281      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
282      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
283  };  };
284    
285  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
286      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
287      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
288      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
289      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
290      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
291      0,    /* needsBootPrefix */  };
292      1,    /* argsInQuotes */  
293      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
294      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
295        .keywords = extlinuxKeywords,
296        .entryStart = LT_TITLE,
297        .needsBootPrefix = 1,
298        .maxTitleLength = 255,
299        .mbAllowExtraInitRds = 1,
300  };  };
301    
302  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 311  struct grubConfig {
311      struct configFileInfo * cfi;      struct configFileInfo * cfi;
312  };  };
313    
314    blkid_cache blkid;
315    
316  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
317  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
318       const char * path, const char * prefix,       const char * path, const char * prefix,
319       int * index);       int * index);
 static char * strndup(char * from, int len);  
320  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
321  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
322    struct singleLine * lineDup(struct singleLine * line);
323  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
324  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
325       struct configFileInfo * cfi);       struct configFileInfo * cfi);
326  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
327         struct configFileInfo * cfi);         struct configFileInfo * cfi);
328  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
329    static void insertElement(struct singleLine * line,
330  static char * strndup(char * from, int len) {    const char * item, int insertHere,
331      char * to;    struct configFileInfo * cfi);
332    static void removeElement(struct singleLine * line, int removeHere);
333      to = malloc(len + 1);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
334      strncpy(to, from, len);        struct configFileInfo * cfi);
335      to[len] = '\0';  static enum lineType_e getTypeByKeyword(char * keyword,
336     struct configFileInfo * cfi);
337      return to;  static struct singleLine * getLineByType(enum lineType_e type,
338  }   struct singleLine * line);
339    static int checkForExtLinux(struct grubConfig * config);
340    struct singleLine * addLineTmpl(struct singleEntry * entry,
341                                    struct singleLine * tmplLine,
342                                    struct singleLine * prevLine,
343                                    const char * val,
344     struct configFileInfo * cfi);
345    struct singleLine *  addLine(struct singleEntry * entry,
346                                 struct configFileInfo * cfi,
347                                 enum lineType_e type, char * defaultIndent,
348                                 const char * val);
349    
350  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
351  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 380  static char * sdupprintf(const char *for
380      return buf;      return buf;
381  }  }
382    
383    static struct keywordTypes * getKeywordByType(enum lineType_e type,
384          struct configFileInfo * cfi) {
385        struct keywordTypes * kw;
386        for (kw = cfi->keywords; kw->key; kw++) {
387     if (kw->type == type)
388        return kw;
389        }
390        return NULL;
391    }
392    
393    static char * getpathbyspec(char *device) {
394        if (!blkid)
395            blkid_get_cache(&blkid, NULL);
396    
397        return blkid_get_devname(blkid, device, NULL);
398    }
399    
400    static char * getuuidbydev(char *device) {
401        if (!blkid)
402     blkid_get_cache(&blkid, NULL);
403    
404        return blkid_get_tag_value(blkid, "UUID", device);
405    }
406    
407    static enum lineType_e getTypeByKeyword(char * keyword,
408     struct configFileInfo * cfi) {
409        struct keywordTypes * kw;
410        for (kw = cfi->keywords; kw->key; kw++) {
411     if (!strcmp(keyword, kw->key))
412        return kw->type;
413        }
414        return LT_UNKNOWN;
415    }
416    
417    static struct singleLine * getLineByType(enum lineType_e type,
418     struct singleLine * line) {
419        dbgPrintf("getLineByType(%d): ", type);
420        for (; line; line = line->next) {
421     dbgPrintf("%d:%s ", line->type,
422      line->numElements ? line->elements[0].item : "(empty)");
423     if (line->type & type) break;
424        }
425        dbgPrintf(line ? "\n" : " (failed)\n");
426        return line;
427    }
428    
429  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
430      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
431          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
432          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
433              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 439  static int isBracketedTitle(struct singl
439      return 0;      return 0;
440  }  }
441    
442  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
443                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
444      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
445   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;  
446  }  }
447    
448  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 493  static void lineInit(struct singleLine *
493      line->next = NULL;      line->next = NULL;
494  }  }
495    
496    struct singleLine * lineDup(struct singleLine * line) {
497        int i;
498        struct singleLine * newLine = malloc(sizeof(*newLine));
499    
500        newLine->indent = strdup(line->indent);
501        newLine->next = NULL;
502        newLine->type = line->type;
503        newLine->numElements = line->numElements;
504        newLine->elements = malloc(sizeof(*newLine->elements) *
505           newLine->numElements);
506    
507        for (i = 0; i < newLine->numElements; i++) {
508     newLine->elements[i].indent = strdup(line->elements[i].indent);
509     newLine->elements[i].item = strdup(line->elements[i].item);
510        }
511    
512        return newLine;
513    }
514    
515  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
516      int i;      int i;
517    
# Line 414  static int lineWrite(FILE * out, struct Line 537  static int lineWrite(FILE * out, struct
537      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
538    
539   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
540   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
541        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
542      }      }
543    
544      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 557  static int getNextLine(char ** bufPtr, s
557      char * chptr;      char * chptr;
558      int elementsAlloced = 0;      int elementsAlloced = 0;
559      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
560      int first = 1;      int first = 1;
     int i;  
561    
562      lineFree(line);      lineFree(line);
563    
# Line 489  static int getNextLine(char ** bufPtr, s Line 611  static int getNextLine(char ** bufPtr, s
611      if (!line->numElements)      if (!line->numElements)
612   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
613      else {      else {
614   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
615      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;  
               
616              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
617               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
618              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 648  static int getNextLine(char ** bufPtr, s
648   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
649   line->numElements = 0;   line->numElements = 0;
650      }      }
651     } else {
652     struct keywordTypes *kw;
653    
654     kw = getKeywordByType(line->type, cfi);
655    
656     /* space isn't the only separator, we need to split
657     * elements up more
658     */
659     if (!isspace(kw->separatorChar)) {
660        int i;
661        char indent[2] = "";
662        indent[0] = kw->separatorChar;
663        for (i = 1; i < line->numElements; i++) {
664     char *p;
665     int j;
666     int numNewElements;
667    
668     numNewElements = 0;
669     p = line->elements[i].item;
670     while (*p != '\0') {
671     if (*p == kw->separatorChar)
672     numNewElements++;
673     p++;
674     }
675     if (line->numElements + numNewElements >= elementsAlloced) {
676     elementsAlloced += numNewElements + 5;
677     line->elements = realloc(line->elements,
678        sizeof(*line->elements) * elementsAlloced);
679     }
680    
681     for (j = line->numElements; j > i; j--) {
682     line->elements[j + numNewElements] = line->elements[j];
683     }
684     line->numElements += numNewElements;
685    
686     p = line->elements[i].item;
687     while (*p != '\0') {
688    
689     while (*p != kw->separatorChar && *p != '\0') p++;
690     if (*p == '\0') {
691     break;
692     }
693    
694     free(line->elements[i].indent);
695     line->elements[i].indent = strdup(indent);
696     *p++ = '\0';
697     i++;
698     line->elements[i].item = strdup(p);
699     line->elements[i].indent = strdup("");
700     p = line->elements[i].item;
701     }
702        }
703     }
704   }   }
705      }      }
706    
# Line 595  static struct grubConfig * readConfig(co Line 764  static struct grubConfig * readConfig(co
764      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
765   }   }
766    
767   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi)) {
768      sawEntry = 1;      sawEntry = 1;
769      if (!entry) {      if (!entry) {
770   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 614  static struct grubConfig * readConfig(co Line 783  static struct grubConfig * readConfig(co
783   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_DEFAULT && line->numElements == 2) {
784      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
785      defaultLine = line;      defaultLine = line;
786    
787            } else if (line->type == LT_KERNEL) {
788        /* if by some freak chance this is multiboot and the "module"
789         * lines came earlier in the template, make sure to use LT_HYPER
790         * instead of LT_KERNEL now
791         */
792        if (entry->multiboot)
793     line->type = LT_HYPER;
794    
795          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
796        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
797         * instead, now that we know this is a multiboot entry.
798         * This only applies to grub, but that's the only place we
799         * should find LT_MBMODULE lines anyway.
800         */
801        struct singleLine * l;
802        for (l = entry->lines; l; l = l->next) {
803     if (l->type == LT_HYPER)
804        break;
805     else if (l->type == LT_KERNEL) {
806        l->type = LT_HYPER;
807        break;
808     }
809        }
810              entry->multiboot = 1;              entry->multiboot = 1;
811    
812     } else if (line->type == LT_HYPER) {
813        entry->multiboot = 1;
814    
815   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
816      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
817      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
818    
819   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
820      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
821      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 840  static struct grubConfig * readConfig(co
840      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
841      line->elements[1].item = buf;      line->elements[1].item = buf;
842      line->numElements = 2;      line->numElements = 2;
843    
844   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
845      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
846         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 850  static struct grubConfig * readConfig(co
850   int last, len;   int last, len;
851    
852   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
853      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
854     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
855    
856   last = line->numElements - 1;   last = line->numElements - 1;
857   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
858   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
859      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
860      }      }
   
861   }   }
862    
863   /* 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 877  static struct grubConfig * readConfig(co
877   movedLine = 1;   movedLine = 1;
878   continue; /* without setting 'last' */   continue; /* without setting 'last' */
879   }   }
880    
881   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
882     which was moved, drop it. */     which was moved, drop it. */
883   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 893  static struct grubConfig * readConfig(co
893   entry->lines = line;   entry->lines = line;
894      else      else
895   last->next = line;   last->next = line;
896        dbgPrintf("readConfig added %d to %p\n", line->type, entry);
897   } else {   } else {
898      if (!cfg->theLines)      if (!cfg->theLines)
899   cfg->theLines = line;   cfg->theLines = line;
900      else {      else
901   last->next = line;   last->next = line;
902      }      dbgPrintf("readConfig added %d to cfg\n", line->type);
903   }   }
904    
905   last = line;   last = line;
# Line 730  static struct grubConfig * readConfig(co Line 929  static struct grubConfig * readConfig(co
929                                  extractTitle(line))) break;                                  extractTitle(line))) break;
930                  }                  }
931   i++;   i++;
932     entry = NULL;
933      }      }
934    
935      if (entry) cfg->defaultImage = i;      if (entry){
936            cfg->defaultImage = i;
937        }else{
938            cfg->defaultImage = -1;
939        }
940   }   }
941        } else {
942            cfg->defaultImage = 0;
943      }      }
944    
945      return cfg;      return cfg;
# Line 769  static void writeDefault(FILE * out, cha Line 975  static void writeDefault(FILE * out, cha
975    
976      if (!entry) return;      if (!entry) return;
977    
978      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
979    
980      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
981   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1009  static int writeConfig(struct grubConfig
1009      int rc;      int rc;
1010    
1011      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1012         directory to / */         directory to the dir of the symlink */
1013      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1014      do {      do {
1015   buf = alloca(len + 1);   buf = alloca(len + 1);
1016   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1017   if (rc == len) len += 256;   if (rc == len) len += 256;
1018      } while (rc == len);      } while (rc == len);
1019            
# Line 912  static int numEntries(struct grubConfig Line 1117  static int numEntries(struct grubConfig
1117      return i;      return i;
1118  }  }
1119    
1120    static char *findDiskForRoot()
1121    {
1122        int fd;
1123        char buf[65536];
1124        char *devname;
1125        char *chptr;
1126        int rc;
1127    
1128        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1129            fprintf(stderr, "grubby: failed to open %s: %s\n",
1130                    _PATH_MOUNTED, strerror(errno));
1131            return NULL;
1132        }
1133    
1134        rc = read(fd, buf, sizeof(buf) - 1);
1135        if (rc <= 0) {
1136            fprintf(stderr, "grubby: failed to read %s: %s\n",
1137                    _PATH_MOUNTED, strerror(errno));
1138            close(fd);
1139            return NULL;
1140        }
1141        close(fd);
1142        buf[rc] = '\0';
1143        chptr = buf;
1144    
1145        while (chptr && chptr != buf+rc) {
1146            devname = chptr;
1147    
1148            /*
1149             * The first column of a mtab entry is the device, but if the entry is a
1150             * special device it won't start with /, so move on to the next line.
1151             */
1152            if (*devname != '/') {
1153                chptr = strchr(chptr, '\n');
1154                if (chptr)
1155                    chptr++;
1156                continue;
1157            }
1158    
1159            /* Seek to the next space */
1160            chptr = strchr(chptr, ' ');
1161            if (!chptr) {
1162                fprintf(stderr, "grubby: error parsing %s: %s\n",
1163                        _PATH_MOUNTED, strerror(errno));
1164                return NULL;
1165            }
1166    
1167            /*
1168             * The second column of a mtab entry is the mount point, we are looking
1169             * for '/' obviously.
1170             */
1171            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1172                /*
1173                 * Move back 2, which is the first space after the device name, set
1174                 * it to \0 so strdup will just get the devicename.
1175                 */
1176                chptr -= 2;
1177                *chptr = '\0';
1178                return strdup(devname);
1179            }
1180    
1181            /* Next line */
1182            chptr = strchr(chptr, '\n');
1183            if (chptr)
1184                chptr++;
1185        }
1186    
1187        return NULL;
1188    }
1189    
1190  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1191    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1192      struct singleLine * line;      struct singleLine * line;
1193      char * fullName;      char * fullName;
1194      int i;      int i;
     struct stat sb, sb2;  
1195      char * dev;      char * dev;
     char * end;  
1196      char * rootspec;      char * rootspec;
1197        char * rootdev;
1198    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
       
     if (!line) return 0;  
1199      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) return 0;
1200      if (line->numElements < 2) return 0;  
1201        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1202        if (!line || line->numElements < 2) return 0;
1203    
1204      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1205    
# Line 935  int suitableImage(struct singleEntry * e Line 1207  int suitableImage(struct singleEntry * e
1207        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1208      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1209      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1210              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
                                       strlen(rootspec) : 0));  
1211      if (access(fullName, R_OK)) return 0;      if (access(fullName, R_OK)) return 0;
1212    
1213      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 945  int suitableImage(struct singleEntry * e Line 1216  int suitableImage(struct singleEntry * e
1216   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1217      } else {      } else {
1218   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1219   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1220    
1221   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1222      dev = line->elements[1].item;      dev = line->elements[1].item;
1223   } else {   } else {
1224              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1225      /* 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.
1226      line = entry->lines;       */
1227        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1228    
1229              /* failed to find one */              /* failed to find one */
1230              if (!line) return 0;              if (!line) return 0;
# Line 973  int suitableImage(struct singleEntry * e Line 1240  int suitableImage(struct singleEntry * e
1240   }   }
1241      }      }
1242    
1243      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1244   dev += 6;      if (!dev)
1245            return 0;
1246   /* check which device has this label */  
1247   dev = get_spec_by_volume_label(dev, &i, &i);      rootdev = findDiskForRoot();
1248   if (!dev) return 0;      if (!rootdev)
1249     return 0;
1250    
1251        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1252            free(rootdev);
1253            return 0;
1254      }      }
1255    
1256      if (*dev == '/') {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1257   if (stat(dev, &sb))   free(rootdev);
1258      return 0;          return 0;
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1259      }      }
     stat("/", &sb2);  
1260    
1261      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1262    
1263      return 1;      return 1;
1264  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1302  struct singleEntry * findEntryByPath(str
1302   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1303   if (!entry) return NULL;   if (!entry) return NULL;
1304    
1305   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1306   if (!line) return NULL;   if (!line) return NULL;
1307    
1308   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1344  struct singleEntry * findEntryByPath(str
1344      kernel += 6;      kernel += 6;
1345   }   }
1346    
1347   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1348      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1349    
1350        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1351    
1352      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1353                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1354          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1355                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1356                              kernel + strlen(prefix)))       checkType, line);
1357                      break;   if (!line) break;  /* not found in this entry */
1358              }  
1359                 if (line && line->numElements >= 2) {
1360              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1361              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1362                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1363                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1364                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1365                      if (!strcmp(line->elements[1].item  +   }
1366                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1367    
1368      i++;      /* make sure this entry has a kernel identifier; this skips
1369         * non-Linux boot entries (could find netbsd etc, though, which is
1370         * unfortunate)
1371         */
1372        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1373     break; /* found 'im! */
1374   }   }
1375    
1376   if (index) *index = i;   if (index) *index = i;
1377      }      }
1378    
     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);  
     }  
   
1379      return entry;      return entry;
1380  }  }
1381    
# Line 1286  void displayEntry(struct singleEntry * e Line 1540  void displayEntry(struct singleEntry * e
1540      char * root = NULL;      char * root = NULL;
1541      int i;      int i;
1542    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1543      printf("index=%d\n", index);      printf("index=%d\n", index);
1544    
1545        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1546        if (!line) {
1547            printf("non linux entry\n");
1548            return;
1549        }
1550    
1551      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1552    
1553      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1565  void displayEntry(struct singleEntry * e
1565   }   }
1566   printf("\"\n");   printf("\"\n");
1567      } else {      } else {
1568   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1569   if (line) {   if (line) {
1570      char * s;      char * s;
1571    
# Line 1334  void displayEntry(struct singleEntry * e Line 1589  void displayEntry(struct singleEntry * e
1589      }      }
1590    
1591      if (!root) {      if (!root) {
1592   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1593   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1594      root=line->elements[1].item;      root=line->elements[1].item;
1595      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1604  void displayEntry(struct singleEntry * e
1604   printf("root=%s\n", s);   printf("root=%s\n", s);
1605      }      }
1606    
1607      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1608    
1609      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1610   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1621  int parseSysconfigGrub(int * lbaPtr, cha
1621      char * start;      char * start;
1622      char * param;      char * param;
1623    
1624      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1625      if (!in) return 1;      if (!in) return 1;
1626    
1627      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1683  int displayInfo(struct grubConfig * conf
1683   return 1;   return 1;
1684      }      }
1685    
1686      /* this is a horrible hack to support /etc/sysconfig/grub; there must      /* this is a horrible hack to support /etc/conf.d/grub; there must
1687         be a better way */         be a better way */
1688      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1689   dumpSysconfigGrub();   dumpSysconfigGrub();
1690      } else {      } else {
1691   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1692   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1693      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1694   }   }
1695    
1696   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1697   if (line) printf("lba\n");   if (line) printf("lba\n");
1698      }      }
1699    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1708  int displayInfo(struct grubConfig * conf
1708      return 0;      return 0;
1709  }  }
1710    
1711    struct singleLine * addLineTmpl(struct singleEntry * entry,
1712     struct singleLine * tmplLine,
1713     struct singleLine * prevLine,
1714     const char * val,
1715     struct configFileInfo * cfi)
1716    {
1717        struct singleLine * newLine = lineDup(tmplLine);
1718    
1719        if (val) {
1720     /* override the inherited value with our own.
1721     * This is a little weak because it only applies to elements[1]
1722     */
1723     if (newLine->numElements > 1)
1724        removeElement(newLine, 1);
1725     insertElement(newLine, val, 1, cfi);
1726    
1727     /* but try to keep the rootspec from the template... sigh */
1728     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1729        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1730        if (rootspec != NULL) {
1731     free(newLine->elements[1].item);
1732     newLine->elements[1].item =
1733        sdupprintf("%s%s", rootspec, val);
1734        }
1735     }
1736        }
1737    
1738        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1739          newLine->elements[0].item : "");
1740    
1741        if (!entry->lines) {
1742     /* first one on the list */
1743     entry->lines = newLine;
1744        } else if (prevLine) {
1745     /* add after prevLine */
1746     newLine->next = prevLine->next;
1747     prevLine->next = newLine;
1748        }
1749    
1750        return newLine;
1751    }
1752    
1753  /* val may be NULL */  /* val may be NULL */
1754  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1755       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1756       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1757       char * val) {       const char * val) {
1758      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1759      int i;      struct keywordTypes * kw;
1760        struct singleLine tmpl;
1761    
1762      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1763   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1764      if (type != LT_TITLE || !cfi->titleBracketed)       */
1765          if (!cfi->keywords[i].key) abort();  
1766        if (type == LT_TITLE && cfi->titleBracketed) {
1767     /* we're doing a bracketed title (zipl) */
1768     tmpl.type = type;
1769     tmpl.numElements = 1;
1770     tmpl.elements = alloca(sizeof(*tmpl.elements));
1771     tmpl.elements[0].item = alloca(strlen(val)+3);
1772     sprintf(tmpl.elements[0].item, "[%s]", val);
1773     tmpl.elements[0].indent = "";
1774     val = NULL;
1775        } else {
1776     kw = getKeywordByType(type, cfi);
1777     if (!kw) abort();
1778     tmpl.type = type;
1779     tmpl.numElements = val ? 2 : 1;
1780     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1781     tmpl.elements[0].item = kw->key;
1782     tmpl.elements[0].indent = alloca(2);
1783     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1784     if (val) {
1785        tmpl.elements[1].item = (char *)val;
1786        tmpl.elements[1].indent = "";
1787     }
1788        }
1789    
1790      /* 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
1791         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1792         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
1793         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1794         differently from the rest) */         differently from the rest) */
1795      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1796   line = entry->lines;   if (line->numElements) prev = line;
1797   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1798   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;  
1799      }      }
1800    
1801      if (type != LT_TITLE || !cfi->titleBracketed) {      if (prev == entry->lines)
1802          line->type = type;   tmpl.indent = defaultIndent ?: "";
1803          line->numElements = val ? 2 : 1;      else
1804          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("");  
     }  
1805    
1806      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1807  }  }
1808    
1809  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 1828  void removeLine(struct singleEntry * ent
1828      free(line);      free(line);
1829  }  }
1830    
1831    static void insertElement(struct singleLine * line,
1832      const char * item, int insertHere,
1833      struct configFileInfo * cfi)
1834    {
1835        struct keywordTypes * kw;
1836        char indent[2] = "";
1837    
1838        /* sanity check */
1839        if (insertHere > line->numElements) {
1840     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
1841      insertHere, line->numElements);
1842     insertHere = line->numElements;
1843        }
1844    
1845        line->elements = realloc(line->elements, (line->numElements + 1) *
1846         sizeof(*line->elements));
1847        memmove(&line->elements[insertHere+1],
1848        &line->elements[insertHere],
1849        (line->numElements - insertHere) *
1850        sizeof(*line->elements));
1851        line->elements[insertHere].item = strdup(item);
1852    
1853        kw = getKeywordByType(line->type, cfi);
1854    
1855        if (line->numElements == 0) {
1856     indent[0] = '\0';
1857        } else if (insertHere == 0) {
1858     indent[0] = kw->nextChar;
1859        } else if (kw->separatorChar != '\0') {
1860     indent[0] = kw->separatorChar;
1861        } else {
1862     indent[0] = ' ';
1863        }
1864    
1865        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
1866     /* move the end-of-line forward */
1867     line->elements[insertHere].indent =
1868        line->elements[insertHere-1].indent;
1869     line->elements[insertHere-1].indent = strdup(indent);
1870        } else {
1871     line->elements[insertHere].indent = strdup(indent);
1872        }
1873    
1874        line->numElements++;
1875    
1876        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
1877          line->elements[0].item,
1878          line->elements[insertHere].item,
1879          line->elements[insertHere].indent,
1880          insertHere);
1881    }
1882    
1883    static void removeElement(struct singleLine * line, int removeHere) {
1884        int i;
1885    
1886        /* sanity check */
1887        if (removeHere >= line->numElements) return;
1888    
1889        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
1890          removeHere, line->elements[removeHere].item);
1891    
1892        free(line->elements[removeHere].item);
1893    
1894        if (removeHere > 1) {
1895     /* previous argument gets this argument's post-indentation */
1896     free(line->elements[removeHere-1].indent);
1897     line->elements[removeHere-1].indent =
1898        line->elements[removeHere].indent;
1899        } else {
1900     free(line->elements[removeHere].indent);
1901        }
1902    
1903        /* now collapse the array, but don't bother to realloc smaller */
1904        for (i = removeHere; i < line->numElements - 1; i++)
1905     line->elements[i] = line->elements[i + 1];
1906    
1907        line->numElements--;
1908    }
1909    
1910  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
1911      char * first, * second;      char * first, * second;
1912      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 1929  int updateActualImage(struct grubConfig
1929      struct singleEntry * entry;      struct singleEntry * entry;
1930      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
1931      int index = 0;      int index = 0;
1932      int i, j, k;      int i, k;
1933      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
1934      const char ** arg;      const char ** arg;
1935      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
1936      int firstElement;      int firstElement;
1937      int *usedElements, *usedArgs;      int *usedElements;
1938        int doreplace;
1939    
1940      if (!image) return 0;      if (!image) return 0;
1941    
# Line 1609  int updateActualImage(struct grubConfig Line 1962  int updateActualImage(struct grubConfig
1962   }   }
1963      }      }
1964    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
1965    
1966      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
1967   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
1968    
1969      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
1970   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
1971    
1972      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
1973    
1974      k = 0;   if (multibootArgs && !entry->multiboot)
1975      for (arg = newArgs; *arg; arg++)      continue;
1976          k++;  
1977      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
1978     * LT_KERNELARGS, use that.  Otherwise use
1979     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
1980     */
1981     if (useKernelArgs) {
1982        line = getLineByType(LT_KERNELARGS, entry->lines);
1983        if (!line) {
1984     /* no LT_KERNELARGS, need to add it */
1985     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
1986           cfg->secondaryIndent, NULL);
1987        }
1988        firstElement = 1;
1989    
1990      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
1991   index++;      line = getLineByType(LT_HYPER, entry->lines);
1992        if (!line) {
1993     /* a multiboot entry without LT_HYPER? */
1994     continue;
1995        }
1996        firstElement = 2;
1997    
1998   line = entry->lines;   } else {
1999   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2000   if (!line) continue;      if (!line) {
2001   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2002     continue;
2003          if (entry->multiboot && !multibootArgs) {      }
2004              /* 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;  
2005   }   }
2006    
2007   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2008      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2009      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2010     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2011        /* this is a multiboot entry, make sure there's
2012         * -- on the args line
2013         */
2014        for (i = firstElement; i < line->numElements; i++) {
2015     if (!strcmp(line->elements[i].item, "--"))
2016        break;
2017        }
2018        if (i == line->numElements) {
2019     /* assume all existing args are kernel args,
2020     * prepend -- to make it official
2021     */
2022     insertElement(line, "--", firstElement, cfg->cfi);
2023     i = firstElement;
2024        }
2025        if (!multibootArgs) {
2026     /* kernel args start after the -- */
2027     firstElement = i + 1;
2028        }
2029     } else if (cfg->cfi->mbConcatArgs) {
2030        /* this is a non-multiboot entry, remove hyper args */
2031        for (i = firstElement; i < line->numElements; i++) {
2032     if (!strcmp(line->elements[i].item, "--"))
2033        break;
2034        }
2035        if (i < line->numElements) {
2036     /* remove args up to -- */
2037     while (strcmp(line->elements[firstElement].item, "--"))
2038        removeElement(line, firstElement);
2039     /* remove -- */
2040     removeElement(line, firstElement);
2041        }
2042   }   }
2043    
2044          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2045    
2046          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2047   for (arg = newArgs; *arg; arg++) {  
2048              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2049      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2050     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2051        !strcmp(line->elements[i].item, "--"))
2052     {
2053        /* reached the end of hyper args, insert here */
2054        doreplace = 0;
2055        break;  
2056     }
2057                  if (usedElements[i])                  if (usedElements[i])
2058                      continue;                      continue;
2059   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2060                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2061      break;      break;
2062                  }                  }
2063              }              }
     chptr = strchr(*arg, '=');  
2064    
2065      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2066   /* replace */   /* direct replacement */
2067   free(line->elements[i].item);   free(line->elements[i].item);
2068   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("");  
  }  
2069    
2070   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2071   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2072      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2073   /* append */   if (rootLine) {
2074   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2075   (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(" ");  
2076   } else {   } else {
2077      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2078         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2079   }   }
2080        }
2081    
2082   line->numElements++;      else {
2083     /* insert/append */
2084     insertElement(line, *arg, i, cfg->cfi);
2085     usedElements = realloc(usedElements, line->numElements *
2086           sizeof(*usedElements));
2087     memmove(&usedElements[i + 1], &usedElements[i],
2088     line->numElements - i - 1);
2089     usedElements[i] = 1;
2090    
2091   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2092     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2093     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2094   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2095      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2096      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2097   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2098   }   }
2099      }      }
             k++;  
2100   }   }
2101    
2102          free(usedElements);          free(usedElements);
2103    
  /* 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? */  
2104   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2105      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2106   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2107        !strcmp(line->elements[i].item, "--"))
2108        /* reached the end of hyper args, stop here */
2109        break;
2110     if (!argMatch(line->elements[i].item, *arg)) {
2111        removeElement(line, i);
2112      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;  
2113   }   }
2114        }
2115   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2116        if (useRoot && !strncmp(*arg, "root=", 5)) {
2117   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2118      line->elements[j - 1] = line->elements[j];   if (rootLine)
2119        removeLine(entry, rootLine);
  line->numElements--;  
2120      }      }
2121   }   }
2122    
# Line 1760  int updateActualImage(struct grubConfig Line 2127  int updateActualImage(struct grubConfig
2127   }   }
2128      }      }
2129    
     free(usedArgs);  
2130      free(newArgs);      free(newArgs);
2131      free(oldArgs);      free(oldArgs);
2132    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2152  int updateImage(struct grubConfig * cfg,
2152      return rc;      return rc;
2153  }  }
2154    
2155    int updateInitrd(struct grubConfig * cfg, const char * image,
2156                     const char * prefix, const char * initrd) {
2157        struct singleEntry * entry;
2158        struct singleLine * line, * kernelLine;
2159        int index = 0;
2160    
2161        if (!image) return 0;
2162    
2163        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2164            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2165            if (!kernelLine) continue;
2166    
2167            line = getLineByType(LT_INITRD, entry->lines);
2168            if (line)
2169                removeLine(entry, line);
2170            if (prefix) {
2171                int prefixLen = strlen(prefix);
2172                if (!strncmp(initrd, prefix, prefixLen))
2173                    initrd += prefixLen;
2174            }
2175            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2176            if (!line) return 1;
2177            break;
2178        }
2179    
2180        return 0;
2181    }
2182    
2183  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2184      int fd;      int fd;
2185      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2370  int checkForGrub(struct grubConfig * con
2370      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2371   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2372   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2373     close(fd);
2374     return 1;
2375        }
2376        close(fd);
2377    
2378        return checkDeviceBootloader(boot, bootSect);
2379    }
2380    
2381    int checkForExtLinux(struct grubConfig * config) {
2382        int fd;
2383        unsigned char bootSect[512];
2384        char * boot;
2385        char executable[] = "/boot/extlinux/extlinux";
2386    
2387        printf("entered: checkForExtLinux()\n");
2388    
2389        if (parseSysconfigGrub(NULL, &boot))
2390     return 0;
2391    
2392        /* assume grub is not installed -- not an error condition */
2393        if (!boot)
2394     return 0;
2395    
2396        fd = open(executable, O_RDONLY);
2397        if (fd < 0)
2398     /* this doesn't exist if grub hasn't been installed */
2399     return 0;
2400    
2401        if (read(fd, bootSect, 512) != 512) {
2402     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2403     executable, strerror(errno));
2404   return 1;   return 1;
2405      }      }
2406      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2419  static char * getRootSpecifier(char * st
2419      return rootspec;      return rootspec;
2420  }  }
2421    
2422    static char * getInitrdVal(struct grubConfig * config,
2423       const char * prefix, struct singleLine *tmplLine,
2424       const char * newKernelInitrd,
2425       char ** extraInitrds, int extraInitrdCount)
2426    {
2427        char *initrdVal, *end;
2428        int i;
2429        size_t totalSize;
2430        size_t prefixLen;
2431        char separatorChar;
2432    
2433        prefixLen = strlen(prefix);
2434        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2435    
2436        for (i = 0; i < extraInitrdCount; i++) {
2437     totalSize += sizeof(separatorChar);
2438     totalSize += strlen(extraInitrds[i]) - prefixLen;
2439        }
2440    
2441        initrdVal = end = malloc(totalSize);
2442    
2443        end = stpcpy (end, newKernelInitrd + prefixLen);
2444    
2445        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2446        for (i = 0; i < extraInitrdCount; i++) {
2447     const char *extraInitrd;
2448     int j;
2449    
2450     extraInitrd = extraInitrds[i] + prefixLen;
2451     /* Don't add entries that are already there */
2452     if (tmplLine != NULL) {
2453        for (j = 2; j < tmplLine->numElements; j++)
2454     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2455        break;
2456    
2457        if (j != tmplLine->numElements)
2458     continue;
2459     }
2460    
2461     *end++ = separatorChar;
2462     end = stpcpy(end, extraInitrd);
2463        }
2464    
2465        return initrdVal;
2466    }
2467    
2468  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2469           const char * prefix,           const char * prefix,
2470   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2471   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2472     char ** extraInitrds, int extraInitrdCount,
2473                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2474      struct singleEntry * new;      struct singleEntry * new;
2475      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2476      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2477      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2478    
2479      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2480    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2504  int addNewKernel(struct grubConfig * con
2504      config->entries = new;      config->entries = new;
2505    
2506      /* copy/update from the template */      /* copy/update from the template */
2507      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2508        if (newKernelInitrd)
2509     needs |= NEED_INITRD;
2510      if (newMBKernel) {      if (newMBKernel) {
2511          needs |= KERNEL_MB;          needs |= NEED_MB;
2512          new->multiboot = 1;          new->multiboot = 1;
2513      }      }
2514    
2515      if (template) {      if (template) {
2516   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2517      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2518      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2519   indent = tmplLine->indent;   {
2520        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2521    
2522      /* skip comments */      /* skip comments */
2523      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2524      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2525      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2526    
2527      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2528      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   tmplLine->numElements >= 2) {
2529     if (!template->multiboot && (needs & NEED_MB)) {
2530              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2531                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2532                  struct singleLine *l;       * hypervisor at the same time.
2533                  needs &= ~ KERNEL_MB;       */
2534        if (config->cfi->mbHyperFirst) {
2535                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2536                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2537                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2538                      newMBKernel + strlen(prefix));
2539                  tmplLine = lastLine;   /* set up for adding the kernel line */
2540                  if (!new->lines) {   free(tmplLine->indent);
2541                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2542                  } else {   needs &= ~NEED_MB;
2543                      newLine->next = l;      }
2544                      newLine = l;      if (needs & NEED_KERNEL) {
2545                  }   /* use addLineTmpl to preserve line elements,
2546                  continue;   * otherwise we could just call addLine.  Unfortunately
2547              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2548                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2549                  continue; /* don't need multiboot kernel here */   * change below.
2550              }   */
2551     struct keywordTypes * mbm_kw =
2552        getKeywordByType(LT_MBMODULE, config->cfi);
2553     if (mbm_kw) {
2554        tmplLine->type = LT_MBMODULE;
2555        free(tmplLine->elements[0].item);
2556        tmplLine->elements[0].item = strdup(mbm_kw->key);
2557     }
2558     newLine = addLineTmpl(new, tmplLine, newLine,
2559          newKernelPath + strlen(prefix), config->cfi);
2560     needs &= ~NEED_KERNEL;
2561        }
2562        if (needs & NEED_MB) { /* !mbHyperFirst */
2563     newLine = addLine(new, config->cfi, LT_HYPER,
2564      config->secondaryIndent,
2565      newMBKernel + strlen(prefix));
2566     needs &= ~NEED_MB;
2567        }
2568     } else if (needs & NEED_KERNEL) {
2569        newLine = addLineTmpl(new, tmplLine, newLine,
2570      newKernelPath + strlen(prefix), config->cfi);
2571        needs &= ~NEED_KERNEL;
2572     }
2573    
2574      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2575   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2576   new->lines = newLine;   if (needs & NEED_MB) {
2577      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2578   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2579   newLine = newLine->next;      needs &= ~NEED_MB;
2580      }   }
2581    
2582        } else if (tmplLine->type == LT_MBMODULE &&
2583           tmplLine->numElements >= 2) {
2584     if (new->multiboot) {
2585        if (needs & NEED_KERNEL) {
2586     newLine = addLineTmpl(new, tmplLine, newLine,
2587          newKernelPath +
2588          strlen(prefix), config->cfi);
2589     needs &= ~NEED_KERNEL;
2590        } else if (config->cfi->mbInitRdIsModule &&
2591           (needs & NEED_INITRD)) {
2592     char *initrdVal;
2593     initrdVal = getInitrdVal(config, prefix, tmplLine,
2594     newKernelInitrd, extraInitrds,
2595     extraInitrdCount);
2596     newLine = addLineTmpl(new, tmplLine, newLine,
2597          initrdVal, config->cfi);
2598     free(initrdVal);
2599     needs &= ~NEED_INITRD;
2600        }
2601     } else if (needs & NEED_KERNEL) {
2602        /* template is multi but new is not,
2603         * insert the kernel in the first module slot
2604         */
2605        tmplLine->type = LT_KERNEL;
2606        free(tmplLine->elements[0].item);
2607        tmplLine->elements[0].item =
2608     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2609        newLine = addLineTmpl(new, tmplLine, newLine,
2610      newKernelPath + strlen(prefix), config->cfi);
2611        needs &= ~NEED_KERNEL;
2612     } else if (needs & NEED_INITRD) {
2613        char *initrdVal;
2614        /* template is multi but new is not,
2615         * insert the initrd in the second module slot
2616         */
2617        tmplLine->type = LT_INITRD;
2618        free(tmplLine->elements[0].item);
2619        tmplLine->elements[0].item =
2620     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2621        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2622        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2623        free(initrdVal);
2624        needs &= ~NEED_INITRD;
2625     }
2626    
     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));  
                 }  
2627      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2628      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2629   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2630   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2631                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2632                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2633                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2634                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2635                  }       */
2636                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2637                  if (rootspec != NULL) {   char *initrdVal;
2638                      newLine->elements[1].item = sdupprintf("%s%s",  
2639                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2640                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2641                                                             strlen(prefix));    config->secondaryIndent,
2642                  } else {    initrdVal);
2643                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2644                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2645                  }      }
2646              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2647                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2648   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2649                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2650                      free(newLine->elements[0].item);      free(initrdVal);
2651                      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);  
2652   }   }
2653    
  newLine->elements[1].item = strdup(newKernelTitle);  
  newLine->elements[1].indent = strdup("");  
  newLine->numElements = 2;  
2654      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2655                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2656                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2657                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2658                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2659                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2660                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2661                                             newLine->numElements);     config->cfi->titleBracketed) {
2662        /* addLineTmpl doesn't handle titleBracketed */
2663                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2664                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2665                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2666                  newLine->numElements = 1;   }
2667              }  
2668        } else {
2669     /* pass through other lines from the template */
2670     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2671        }
2672   }   }
2673    
2674      } else {      } else {
2675   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2676      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2677     */
2678     switch (config->cfi->entryStart) {
2679        case LT_KERNEL:
2680     if (new->multiboot && config->cfi->mbHyperFirst) {
2681        /* fall through to LT_HYPER */
2682     } else {
2683        newLine = addLine(new, config->cfi, LT_KERNEL,
2684          config->primaryIndent,
2685          newKernelPath + strlen(prefix));
2686        needs &= ~NEED_KERNEL;
2687        break;
2688     }
2689    
2690        case LT_HYPER:
2691     newLine = addLine(new, config->cfi, LT_HYPER,
2692      config->primaryIndent,
2693      newMBKernel + strlen(prefix));
2694     needs &= ~NEED_MB;
2695   break;   break;
         }  
2696    
2697   switch (config->cfi->keywords[i].type) {      case LT_TITLE:
2698      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
2699       chptr = newKernelPath + strlen(prefix);   char * templabel;
2700       type = LT_KERNEL; break;   int x = 0, y = 0;
2701      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;  
2702       type = LT_TITLE; break;   templabel = strdup(newKernelTitle);
2703      default:       while( templabel[x]){
2704                  /* zipl strikes again */   if( templabel[x] == ' ' ){
2705                  if (config->cfi->titleBracketed) {   y = x;
2706                      needs &= ~KERNEL_TITLE;   while( templabel[y] ){
2707                      chptr = newKernelTitle;   templabel[y] = templabel[y+1];
2708                      type = LT_TITLE;   y++;
2709                      break;   }
2710                  } else {   }
2711                      abort();   x++;
2712                  }   }
2713   }   newLine = addLine(new, config->cfi, LT_TITLE,
2714      config->primaryIndent, templabel);
2715     free(templabel);
2716     }else{
2717     newLine = addLine(new, config->cfi, LT_TITLE,
2718      config->primaryIndent, newKernelTitle);
2719     }
2720     needs &= ~NEED_TITLE;
2721     break;
2722    
2723   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
2724   new->lines = newLine;   abort();
2725     }
2726      }      }
2727    
2728      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
2729          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
2730              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
2731                                config->secondaryIndent,       */
2732                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
2733          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
2734              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
2735                                config->secondaryIndent,    newKernelTitle);
2736                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
2737          /* don't need to check for title as it's guaranteed to have been      }
2738           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
2739           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
2740          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
2741              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
2742                                config->secondaryIndent,   needs &= ~NEED_MB;
2743                                newKernelInitrd + strlen(prefix));      }
2744      } else {      if (needs & NEED_KERNEL) {
2745          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
2746              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
2747                                config->secondaryIndent,        config->cfi)) ?
2748                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
2749          if (needs & KERNEL_TITLE)    config->secondaryIndent,
2750              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
2751                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
2752                                newKernelTitle);      }
2753          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
2754              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
2755                                config->secondaryIndent,    config->secondaryIndent,
2756                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
2757     needs &= ~NEED_MB;
2758        }
2759        if (needs & NEED_INITRD) {
2760     char *initrdVal;
2761     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
2762     newLine = addLine(new, config->cfi,
2763      (new->multiboot && getKeywordByType(LT_MBMODULE,
2764          config->cfi)) ?
2765      LT_MBMODULE : LT_INITRD,
2766      config->secondaryIndent,
2767      initrdVal);
2768     free(initrdVal);
2769     needs &= ~NEED_INITRD;
2770        }
2771    
2772        if (needs) {
2773     printf(_("grubby: needs=%d, aborting\n"), needs);
2774     abort();
2775      }      }
2776    
2777      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 2780  int addNewKernel(struct grubConfig * con
2780      return 0;      return 0;
2781  }  }
2782    
2783    static void traceback(int signum)
2784    {
2785        void *array[40];
2786        size_t size;
2787    
2788        signal(SIGSEGV, SIG_DFL);
2789        memset(array, '\0', sizeof (array));
2790        size = backtrace(array, 40);
2791    
2792        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
2793                (unsigned long)size);
2794        backtrace_symbols_fd(array, size, STDERR_FILENO);
2795        exit(1);
2796    }
2797    
2798  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
2799      poptContext optCon;      poptContext optCon;
2800      char * grubConfig = NULL;      char * grubConfig = NULL;
# Line 2283  int main(int argc, const char ** argv) { Line 2804  int main(int argc, const char ** argv) {
2804      int badImageOkay = 0;      int badImageOkay = 0;
2805      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
2806      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
2807        int configureExtLinux = 0;
2808      int bootloaderProbe = 0;      int bootloaderProbe = 0;
2809        int extraInitrdCount = 0;
2810      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
2811      char * newKernelPath = NULL;      char * newKernelPath = NULL;
2812      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 2822  int main(int argc, const char ** argv) {
2822      char * defaultKernel = NULL;      char * defaultKernel = NULL;
2823      char * removeArgs = NULL;      char * removeArgs = NULL;
2824      char * kernelInfo = NULL;      char * kernelInfo = NULL;
2825        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
2826      const char * chptr = NULL;      const char * chptr = NULL;
2827      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
2828      struct grubConfig * config;      struct grubConfig * config;
# Line 2339  int main(int argc, const char ** argv) { Line 2863  int main(int argc, const char ** argv) {
2863      _("display the path of the default kernel") },      _("display the path of the default kernel") },
2864   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
2865      _("configure elilo bootloader") },      _("configure elilo bootloader") },
2866     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
2867        _("configure extlinux bootloader (from syslinux)") },
2868   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
2869      _("configure grub bootloader") },      _("configure grub bootloader") },
2870   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
# Line 2346  int main(int argc, const char ** argv) { Line 2872  int main(int argc, const char ** argv) {
2872      _("kernel-path") },      _("kernel-path") },
2873   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
2874      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
2875     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
2876        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
2877   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
2878      _("configure lilo bootloader") },      _("configure lilo bootloader") },
2879   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 2910  int main(int argc, const char ** argv) {
2910   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
2911      };      };
2912    
2913        useextlinuxmenu=0;
2914    
2915        signal(SIGSEGV, traceback);
2916    
2917      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
2918      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
2919    
# Line 2391  int main(int argc, const char ** argv) { Line 2923  int main(int argc, const char ** argv) {
2923      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
2924      exit(0);      exit(0);
2925      break;      break;
2926      case 'i':
2927        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
2928         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
2929        } else {
2930     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
2931     return 1;
2932        }
2933        break;
2934   }   }
2935      }      }
2936    
# Line 2407  int main(int argc, const char ** argv) { Line 2947  int main(int argc, const char ** argv) {
2947      }      }
2948    
2949      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub + configureELilo +
2950   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
2951     configureExtLinux ) > 1) {
2952   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
2953   return 1;   return 1;
2954      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
# Line 2426  int main(int argc, const char ** argv) { Line 2967  int main(int argc, const char ** argv) {
2967          cfi = &siloConfigType;          cfi = &siloConfigType;
2968      } else if (configureZipl) {      } else if (configureZipl) {
2969          cfi = &ziplConfigType;          cfi = &ziplConfigType;
2970        } else if (configureExtLinux) {
2971     cfi = &extlinuxConfigType;
2972     useextlinuxmenu=1;
2973      }      }
2974    
2975      if (!cfi) {      if (!cfi) {
# Line 2465  int main(int argc, const char ** argv) { Line 3009  int main(int argc, const char ** argv) {
3009      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3010   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3011   return 1;   return 1;
3012      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3013    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3014    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3015   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3016   return 1;   return 1;
3017      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3064  int main(int argc, const char ** argv) {
3064   bootPrefix = "";   bootPrefix = "";
3065      }      }
3066    
3067        if (!cfi->mbAllowExtraInitRds &&
3068     extraInitrdCount > 0) {
3069     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3070     return 1;
3071        }
3072    
3073      if (bootloaderProbe) {      if (bootloaderProbe) {
3074   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, erc = 0;
3075   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3076    
3077   if (!access(grubConfigType.defaultConfig, F_OK)) {   if (!access(grubConfigType.defaultConfig, F_OK)) {
# Line 2540  int main(int argc, const char ** argv) { Line 3090  int main(int argc, const char ** argv) {
3090   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3091   }   }
3092    
3093     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3094        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3095        if (!lconfig)
3096     erc = 1;
3097        else
3098     erc = checkForExtLinux(lconfig);
3099     }
3100    
3101   if (lrc == 1 || grc == 1) return 1;   if (lrc == 1 || grc == 1) return 1;
3102    
3103   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3104   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3105     if (erc == 2) printf("extlinux\n");
3106    
3107   return 0;   return 0;
3108      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3120  int main(int argc, const char ** argv) {
3120   if (!entry) return 0;   if (!entry) return 0;
3121   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3122    
3123   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3124   if (!line) return 0;   if (!line) return 0;
3125    
3126          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2585  int main(int argc, const char ** argv) { Line 3143  int main(int argc, const char ** argv) {
3143      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3144      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3145                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3146        if (updateKernelPath && newKernelInitrd) {
3147                if (updateInitrd(config, updateKernelPath, bootPrefix,
3148                                 newKernelInitrd)) return 1;
3149        }
3150      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3151                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3152                         extraInitrds, extraInitrdCount,
3153                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3154            
3155    

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