Magellan Linux

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

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