Magellan Linux

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

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

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 1177 by niro, Wed Dec 15 21:16:32 2010 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 */      "/boot/grub/grub.conf",    /* defaultConfig */
143      grubKeywords,    /* keywords */      grubKeywords,    /* keywords */
144      1,    /* defaultIsIndex */      1,    /* defaultIsIndex */
145      1,    /* defaultSupportSaved */      1,    /* defaultSupportSaved */
# Line 109  struct configFileInfo grubConfigType = { Line 148  struct configFileInfo grubConfigType = {
148      0,    /* argsInQuotes */      0,    /* argsInQuotes */
149      0,    /* maxTitleLength */      0,    /* maxTitleLength */
150      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
151        1,                                      /* mbHyperFirst */
152        1,                                      /* mbInitRdIsModule */
153        0,                                      /* mbConcatArgs */
154        1,                                      /* mbAllowExtraInitRds */
155  };  };
156    
157  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 185  struct keywordTypes yabootKeywords[] = {
185      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
186      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
187      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
188      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
189      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
190      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
191      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 205  struct keywordTypes liloKeywords[] = {
205      { NULL,    0, 0 },      { NULL,    0, 0 },
206  };  };
207    
208    struct keywordTypes eliloKeywords[] = {
209        { "label",    LT_TITLE,    '=' },
210        { "root",    LT_ROOT,    '=' },
211        { "default",    LT_DEFAULT,    '=' },
212        { "image",    LT_KERNEL,    '=' },
213        { "initrd",    LT_INITRD,    '=' },
214        { "append",    LT_KERNELARGS,  '=' },
215        { "vmm",    LT_HYPER,       '=' },
216        { NULL,    0, 0 },
217    };
218    
219  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
220      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
221      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 237  struct keywordTypes ziplKeywords[] = {
237      { NULL,         0, 0 },      { NULL,         0, 0 },
238  };  };
239    
240    struct keywordTypes extlinuxKeywords[] = {
241        { "label",    LT_TITLE,    ' ' },
242        { "root",    LT_ROOT,    ' ' },
243        { "default",    LT_DEFAULT,    ' ' },
244        { "kernel",    LT_KERNEL,    ' ' },
245        { "initrd",    LT_INITRD,      ' ', ',' },
246        { "append",    LT_KERNELARGS,  ' ' },
247        { "prompt",     LT_UNKNOWN,     ' ' },
248        { NULL,    0, 0 },
249    };
250    int useextlinuxmenu;
251  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
252      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */
253      liloKeywords,    /* keywords */      eliloKeywords,    /* keywords */
254      0,    /* defaultIsIndex */      0,    /* defaultIsIndex */
255      0,    /* defaultSupportSaved */      0,    /* defaultSupportSaved */
256      LT_KERNEL,    /* entrySeparator */      LT_KERNEL,    /* entrySeparator */
# Line 193  struct configFileInfo eliloConfigType = Line 258  struct configFileInfo eliloConfigType =
258      1,    /* argsInQuotes */      1,    /* argsInQuotes */
259      0,    /* maxTitleLength */      0,    /* maxTitleLength */
260      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
261        0,                                      /* mbHyperFirst */
262        0,                                      /* mbInitRdIsModule */
263        1,                                      /* mbConcatArgs */
264        0,                                      /* mbAllowExtraInitRds */
265  };  };
266    
267  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
# Line 205  struct configFileInfo liloConfigType = { Line 274  struct configFileInfo liloConfigType = {
274      1,    /* argsInQuotes */      1,    /* argsInQuotes */
275      15,    /* maxTitleLength */      15,    /* maxTitleLength */
276      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
277        0,                                      /* mbHyperFirst */
278        0,                                      /* mbInitRdIsModule */
279        0,                                      /* mbConcatArgs */
280        0,                                      /* mbAllowExtraInitRds */
281  };  };
282    
283  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
# Line 217  struct configFileInfo yabootConfigType = Line 290  struct configFileInfo yabootConfigType =
290      1,    /* argsInQuotes */      1,    /* argsInQuotes */
291      15,    /* maxTitleLength */      15,    /* maxTitleLength */
292      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
293        0,                                      /* mbHyperFirst */
294        0,                                      /* mbInitRdIsModule */
295        0,                                      /* mbConcatArgs */
296        1,                                      /* mbAllowExtraInitRds */
297  };  };
298    
299  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
# Line 229  struct configFileInfo siloConfigType = { Line 306  struct configFileInfo siloConfigType = {
306      1,    /* argsInQuotes */      1,    /* argsInQuotes */
307      15,    /* maxTitleLength */      15,    /* maxTitleLength */
308      0,                                      /* titleBracketed */      0,                                      /* titleBracketed */
309        0,                                      /* mbHyperFirst */
310        0,                                      /* mbInitRdIsModule */
311        0,                                      /* mbConcatArgs */
312        0,                                      /* mbAllowExtraInitRds */
313  };  };
314    
315  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
# Line 239  struct configFileInfo ziplConfigType = { Line 320  struct configFileInfo ziplConfigType = {
320      LT_TITLE,    /* entrySeparator */      LT_TITLE,    /* entrySeparator */
321      0,    /* needsBootPrefix */      0,    /* needsBootPrefix */
322      1,    /* argsInQuotes */      1,    /* argsInQuotes */
323      15,    /* maxTitleLength */      0,    /* maxTitleLength */
324      1,                                      /* titleBracketed */      1,                                      /* titleBracketed */
325        0,                                      /* mbHyperFirst */
326        0,                                      /* mbInitRdIsModule */
327        0,                                      /* mbConcatArgs */
328        0,                                      /* mbAllowExtraInitRds */
329    };
330    
331    struct configFileInfo extlinuxConfigType = {
332        "/boot/extlinux/extlinux.conf",         /* defaultConfig */
333        extlinuxKeywords,                       /* keywords */
334        0,                                      /* defaultIsIndex */
335        0,                                      /* defaultSupportSaved */
336        LT_TITLE,                               /* entrySeparator */
337        1,                                      /* needsBootPrefix */
338        0,                                      /* argsInQuotes */
339        255,                                    /* maxTitleLength */
340        0,                                      /* titleBracketed */
341        0,                                      /* mbHyperFirst */
342        0,                                      /* mbInitRdIsModule */
343        0,                                      /* mbConcatArgs */
344        1,                                      /* mbAllowExtraInitRds */
345  };  };
346    
347  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 356  struct grubConfig {
356      struct configFileInfo * cfi;      struct configFileInfo * cfi;
357  };  };
358    
359    blkid_cache blkid;
360    
361  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
362  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
363       const char * path, const char * prefix,       const char * path, const char * prefix,
364       int * index);       int * index);
 static char * strndup(char * from, int len);  
365  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
366  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
367    struct singleLine * lineDup(struct singleLine * line);
368  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
369  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
370       struct configFileInfo * cfi);       struct configFileInfo * cfi);
371  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
372         struct configFileInfo * cfi);         struct configFileInfo * cfi);
373  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
374    static void insertElement(struct singleLine * line,
375  static char * strndup(char * from, int len) {    const char * item, int insertHere,
376      char * to;    struct configFileInfo * cfi);
377    static void removeElement(struct singleLine * line, int removeHere);
378      to = malloc(len + 1);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
379      strncpy(to, from, len);        struct configFileInfo * cfi);
380      to[len] = '\0';  static enum lineType_e getTypeByKeyword(char * keyword,
381     struct configFileInfo * cfi);
382      return to;  static struct singleLine * getLineByType(enum lineType_e type,
383  }   struct singleLine * line);
384    static int checkForExtLinux(struct grubConfig * config);
385    struct singleLine * addLineTmpl(struct singleEntry * entry,
386                                    struct singleLine * tmplLine,
387                                    struct singleLine * prevLine,
388                                    const char * val,
389     struct configFileInfo * cfi);
390    struct singleLine *  addLine(struct singleEntry * entry,
391                                 struct configFileInfo * cfi,
392                                 enum lineType_e type, char * defaultIndent,
393                                 const char * val);
394    
395  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
396  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 425  static char * sdupprintf(const char *for
425      return buf;      return buf;
426  }  }
427    
428    static struct keywordTypes * getKeywordByType(enum lineType_e type,
429          struct configFileInfo * cfi) {
430        struct keywordTypes * kw;
431        for (kw = cfi->keywords; kw->key; kw++) {
432     if (kw->type == type)
433        return kw;
434        }
435        return NULL;
436    }
437    
438    static char * getpathbyspec(char *device) {
439        if (!blkid)
440            blkid_get_cache(&blkid, NULL);
441    
442        return blkid_get_devname(blkid, device, NULL);
443    }
444    
445    static char * getuuidbydev(char *device) {
446        if (!blkid)
447     blkid_get_cache(&blkid, NULL);
448    
449        return blkid_get_tag_value(blkid, "UUID", device);
450    }
451    
452    static enum lineType_e getTypeByKeyword(char * keyword,
453     struct configFileInfo * cfi) {
454        struct keywordTypes * kw;
455        for (kw = cfi->keywords; kw->key; kw++) {
456     if (!strcmp(keyword, kw->key))
457        return kw->type;
458        }
459        return LT_UNKNOWN;
460    }
461    
462    static struct singleLine * getLineByType(enum lineType_e type,
463     struct singleLine * line) {
464        dbgPrintf("getLineByType(%d): ", type);
465        for (; line; line = line->next) {
466     dbgPrintf("%d:%s ", line->type,
467      line->numElements ? line->elements[0].item : "(empty)");
468     if (line->type & type) break;
469        }
470        dbgPrintf(line ? "\n" : " (failed)\n");
471        return line;
472    }
473    
474  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
475      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
476          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
477          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
478              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 484  static int isBracketedTitle(struct singl
484      return 0;      return 0;
485  }  }
486    
 /* figure out if this is a entry separator */  
487  static int isEntrySeparator(struct singleLine * line,  static int isEntrySeparator(struct singleLine * line,
488                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
489      if (line->type == LT_WHITESPACE)      return line->type == cfi->entrySeparator || line->type == LT_OTHER ||
490   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;  
491  }  }
492    
493  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 538  static void lineInit(struct singleLine *
538      line->next = NULL;      line->next = NULL;
539  }  }
540    
541    struct singleLine * lineDup(struct singleLine * line) {
542        int i;
543        struct singleLine * newLine = malloc(sizeof(*newLine));
544    
545        newLine->indent = strdup(line->indent);
546        newLine->next = NULL;
547        newLine->type = line->type;
548        newLine->numElements = line->numElements;
549        newLine->elements = malloc(sizeof(*newLine->elements) *
550           newLine->numElements);
551    
552        for (i = 0; i < newLine->numElements; i++) {
553     newLine->elements[i].indent = strdup(line->elements[i].indent);
554     newLine->elements[i].item = strdup(line->elements[i].item);
555        }
556    
557        return newLine;
558    }
559    
560  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
561      int i;      int i;
562    
# Line 414  static int lineWrite(FILE * out, struct Line 582  static int lineWrite(FILE * out, struct
582      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
583    
584   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
585   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
586        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
587      }      }
588    
589      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 602  static int getNextLine(char ** bufPtr, s
602      char * chptr;      char * chptr;
603      int elementsAlloced = 0;      int elementsAlloced = 0;
604      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
605      int first = 1;      int first = 1;
     int i;  
606    
607      lineFree(line);      lineFree(line);
608    
# Line 489  static int getNextLine(char ** bufPtr, s Line 656  static int getNextLine(char ** bufPtr, s
656      if (!line->numElements)      if (!line->numElements)
657   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
658      else {      else {
659   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
660      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;  
               
661              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
662               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
663              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 693  static int getNextLine(char ** bufPtr, s
693   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
694   line->numElements = 0;   line->numElements = 0;
695      }      }
696     } else {
697     struct keywordTypes *kw;
698    
699     kw = getKeywordByType(line->type, cfi);
700    
701     /* space isn't the only separator, we need to split
702     * elements up more
703     */
704     if (!isspace(kw->separatorChar)) {
705        int i;
706        char indent[2] = "";
707        indent[0] = kw->separatorChar;
708        for (i = 1; i < line->numElements; i++) {
709     char *p;
710     int j;
711     int numNewElements;
712    
713     numNewElements = 0;
714     p = line->elements[i].item;
715     while (*p != '\0') {
716     if (*p == kw->separatorChar)
717     numNewElements++;
718     p++;
719     }
720     if (line->numElements + numNewElements >= elementsAlloced) {
721     elementsAlloced += numNewElements + 5;
722     line->elements = realloc(line->elements,
723        sizeof(*line->elements) * elementsAlloced);
724     }
725    
726     for (j = line->numElements; j > i; j--) {
727     line->elements[j + numNewElements] = line->elements[j];
728     }
729     line->numElements += numNewElements;
730    
731     p = line->elements[i].item;
732     while (*p != '\0') {
733    
734     while (*p != kw->separatorChar && *p != '\0') p++;
735     if (*p == '\0') {
736     break;
737     }
738    
739     free(line->elements[i].indent);
740     line->elements[i].indent = strdup(indent);
741     *p++ = '\0';
742     i++;
743     line->elements[i].item = strdup(p);
744     line->elements[i].indent = strdup("");
745     p = line->elements[i].item;
746     }
747        }
748     }
749   }   }
750      }      }
751    
# Line 614  static struct grubConfig * readConfig(co Line 828  static struct grubConfig * readConfig(co
828   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_DEFAULT && line->numElements == 2) {
829      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
830      defaultLine = line;      defaultLine = line;
831    
832            } else if (line->type == LT_KERNEL) {
833        /* if by some freak chance this is multiboot and the "module"
834         * lines came earlier in the template, make sure to use LT_HYPER
835         * instead of LT_KERNEL now
836         */
837        if (entry->multiboot)
838     line->type = LT_HYPER;
839    
840          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
841        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
842         * instead, now that we know this is a multiboot entry.
843         * This only applies to grub, but that's the only place we
844         * should find LT_MBMODULE lines anyway.
845         */
846        struct singleLine * l;
847        for (l = entry->lines; l; l = l->next) {
848     if (l->type == LT_HYPER)
849        break;
850     else if (l->type == LT_KERNEL) {
851        l->type = LT_HYPER;
852        break;
853     }
854        }
855              entry->multiboot = 1;              entry->multiboot = 1;
856    
857     } else if (line->type == LT_HYPER) {
858        entry->multiboot = 1;
859    
860   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
861      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
862      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
863    
864   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
865      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
866      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 885  static struct grubConfig * readConfig(co
885      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
886      line->elements[1].item = buf;      line->elements[1].item = buf;
887      line->numElements = 2;      line->numElements = 2;
888    
889   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
890      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
891         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 895  static struct grubConfig * readConfig(co
895   int last, len;   int last, len;
896    
897   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
898      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
899     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
900    
901   last = line->numElements - 1;   last = line->numElements - 1;
902   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
903   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
904      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
905      }      }
   
906   }   }
907    
908   /* 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 922  static struct grubConfig * readConfig(co
922   movedLine = 1;   movedLine = 1;
923   continue; /* without setting 'last' */   continue; /* without setting 'last' */
924   }   }
925    
926   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
927     which was moved, drop it. */     which was moved, drop it. */
928   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 938  static struct grubConfig * readConfig(co
938   entry->lines = line;   entry->lines = line;
939      else      else
940   last->next = line;   last->next = line;
941        dbgPrintf("readConfig added %d to %p\n", line->type, entry);
942   } else {   } else {
943      if (!cfg->theLines)      if (!cfg->theLines)
944   cfg->theLines = line;   cfg->theLines = line;
945      else {      else
946   last->next = line;   last->next = line;
947      }      dbgPrintf("readConfig added %d to cfg\n", line->type);
948   }   }
949    
950   last = line;   last = line;
# Line 730  static struct grubConfig * readConfig(co Line 974  static struct grubConfig * readConfig(co
974                                  extractTitle(line))) break;                                  extractTitle(line))) break;
975                  }                  }
976   i++;   i++;
977     entry = NULL;
978      }      }
979    
980      if (entry) cfg->defaultImage = i;      if (entry){
981            cfg->defaultImage = i;
982        }else{
983            cfg->defaultImage = -1;
984        }
985   }   }
986        } else {
987            cfg->defaultImage = 0;
988      }      }
989    
990      return cfg;      return cfg;
# Line 769  static void writeDefault(FILE * out, cha Line 1020  static void writeDefault(FILE * out, cha
1020    
1021      if (!entry) return;      if (!entry) return;
1022    
1023      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1024    
1025      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1026   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1054  static int writeConfig(struct grubConfig
1054      int rc;      int rc;
1055    
1056      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1057         directory to / */         directory to the dir of the symlink */
1058      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1059      do {      do {
1060   buf = alloca(len + 1);   buf = alloca(len + 1);
1061   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1062   if (rc == len) len += 256;   if (rc == len) len += 256;
1063      } while (rc == len);      } while (rc == len);
1064            
# Line 912  static int numEntries(struct grubConfig Line 1162  static int numEntries(struct grubConfig
1162      return i;      return i;
1163  }  }
1164    
1165    static char *findDiskForRoot()
1166    {
1167        int fd;
1168        char buf[65536];
1169        char *devname;
1170        char *chptr;
1171        int rc;
1172    
1173        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1174            fprintf(stderr, "grubby: failed to open %s: %s\n",
1175                    _PATH_MOUNTED, strerror(errno));
1176            return NULL;
1177        }
1178    
1179        rc = read(fd, buf, sizeof(buf) - 1);
1180        if (rc <= 0) {
1181            fprintf(stderr, "grubby: failed to read %s: %s\n",
1182                    _PATH_MOUNTED, strerror(errno));
1183            close(fd);
1184            return NULL;
1185        }
1186        close(fd);
1187        buf[rc] = '\0';
1188        chptr = buf;
1189    
1190        while (chptr && chptr != buf+rc) {
1191            devname = chptr;
1192    
1193            /*
1194             * The first column of a mtab entry is the device, but if the entry is a
1195             * special device it won't start with /, so move on to the next line.
1196             */
1197            if (*devname != '/') {
1198                chptr = strchr(chptr, '\n');
1199                if (chptr)
1200                    chptr++;
1201                continue;
1202            }
1203    
1204            /* Seek to the next space */
1205            chptr = strchr(chptr, ' ');
1206            if (!chptr) {
1207                fprintf(stderr, "grubby: error parsing %s: %s\n",
1208                        _PATH_MOUNTED, strerror(errno));
1209                return NULL;
1210            }
1211    
1212            /*
1213             * The second column of a mtab entry is the mount point, we are looking
1214             * for '/' obviously.
1215             */
1216            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1217                /*
1218                 * Move back 2, which is the first space after the device name, set
1219                 * it to \0 so strdup will just get the devicename.
1220                 */
1221                chptr -= 2;
1222                *chptr = '\0';
1223                return strdup(devname);
1224            }
1225    
1226            /* Next line */
1227            chptr = strchr(chptr, '\n');
1228            if (chptr)
1229                chptr++;
1230        }
1231    
1232        return NULL;
1233    }
1234    
1235  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1236    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1237      struct singleLine * line;      struct singleLine * line;
1238      char * fullName;      char * fullName;
1239      int i;      int i;
     struct stat sb, sb2;  
1240      char * dev;      char * dev;
     char * end;  
1241      char * rootspec;      char * rootspec;
1242        char * rootdev;
1243    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
       
     if (!line) return 0;  
1244      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) return 0;
1245      if (line->numElements < 2) return 0;  
1246        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1247        if (!line || line->numElements < 2) return 0;
1248    
1249      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1250    
# Line 935  int suitableImage(struct singleEntry * e Line 1252  int suitableImage(struct singleEntry * e
1252        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1253      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1254      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1255              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
                                       strlen(rootspec) : 0));  
1256      if (access(fullName, R_OK)) return 0;      if (access(fullName, R_OK)) return 0;
1257    
1258      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 945  int suitableImage(struct singleEntry * e Line 1261  int suitableImage(struct singleEntry * e
1261   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1262      } else {      } else {
1263   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1264   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1265    
1266   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1267      dev = line->elements[1].item;      dev = line->elements[1].item;
1268   } else {   } else {
1269              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1270      /* 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.
1271      line = entry->lines;       */
1272        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1273    
1274              /* failed to find one */              /* failed to find one */
1275              if (!line) return 0;              if (!line) return 0;
# Line 973  int suitableImage(struct singleEntry * e Line 1285  int suitableImage(struct singleEntry * e
1285   }   }
1286      }      }
1287    
1288      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1289   dev += 6;      if (!dev)
1290            return 0;
1291   /* check which device has this label */  
1292   dev = get_spec_by_volume_label(dev, &i, &i);      rootdev = findDiskForRoot();
1293   if (!dev) return 0;      if (!rootdev)
1294     return 0;
1295    
1296        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1297            free(rootdev);
1298            return 0;
1299      }      }
1300    
1301      if (*dev == '/') {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1302   if (stat(dev, &sb))   free(rootdev);
1303      return 0;          return 0;
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1304      }      }
     stat("/", &sb2);  
1305    
1306      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1307    
1308      return 1;      return 1;
1309  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1347  struct singleEntry * findEntryByPath(str
1347   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1348   if (!entry) return NULL;   if (!entry) return NULL;
1349    
1350   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1351   if (!line) return NULL;   if (!line) return NULL;
1352    
1353   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1389  struct singleEntry * findEntryByPath(str
1389      kernel += 6;      kernel += 6;
1390   }   }
1391    
1392   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1393      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1394    
1395        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1396    
1397      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1398                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1399          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1400                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1401                              kernel + strlen(prefix)))       checkType, line);
1402                      break;   if (!line) break;  /* not found in this entry */
1403              }  
1404                 if (line && line->numElements >= 2) {
1405              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1406              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1407                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1408                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1409                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1410                      if (!strcmp(line->elements[1].item  +   }
1411                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1412    
1413      i++;      /* make sure this entry has a kernel identifier; this skips
1414         * non-Linux boot entries (could find netbsd etc, though, which is
1415         * unfortunate)
1416         */
1417        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1418     break; /* found 'im! */
1419   }   }
1420    
1421   if (index) *index = i;   if (index) *index = i;
1422      }      }
1423    
     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);  
     }  
   
1424      return entry;      return entry;
1425  }  }
1426    
# Line 1286  void displayEntry(struct singleEntry * e Line 1585  void displayEntry(struct singleEntry * e
1585      char * root = NULL;      char * root = NULL;
1586      int i;      int i;
1587    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1588      printf("index=%d\n", index);      printf("index=%d\n", index);
1589    
1590        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1591        if (!line) {
1592            printf("non linux entry\n");
1593            return;
1594        }
1595    
1596      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1597    
1598      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1610  void displayEntry(struct singleEntry * e
1610   }   }
1611   printf("\"\n");   printf("\"\n");
1612      } else {      } else {
1613   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1614   if (line) {   if (line) {
1615      char * s;      char * s;
1616    
# Line 1334  void displayEntry(struct singleEntry * e Line 1634  void displayEntry(struct singleEntry * e
1634      }      }
1635    
1636      if (!root) {      if (!root) {
1637   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1638   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1639      root=line->elements[1].item;      root=line->elements[1].item;
1640      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1649  void displayEntry(struct singleEntry * e
1649   printf("root=%s\n", s);   printf("root=%s\n", s);
1650      }      }
1651    
1652      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1653    
1654      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1655   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1666  int parseSysconfigGrub(int * lbaPtr, cha
1666      char * start;      char * start;
1667      char * param;      char * param;
1668    
1669      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1670      if (!in) return 1;      if (!in) return 1;
1671    
1672      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1728  int displayInfo(struct grubConfig * conf
1728   return 1;   return 1;
1729      }      }
1730    
1731      /* 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
1732         be a better way */         be a better way */
1733      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1734   dumpSysconfigGrub();   dumpSysconfigGrub();
1735      } else {      } else {
1736   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1737   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1738      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1739   }   }
1740    
1741   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1742   if (line) printf("lba\n");   if (line) printf("lba\n");
1743      }      }
1744    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1753  int displayInfo(struct grubConfig * conf
1753      return 0;      return 0;
1754  }  }
1755    
1756    struct singleLine * addLineTmpl(struct singleEntry * entry,
1757     struct singleLine * tmplLine,
1758     struct singleLine * prevLine,
1759     const char * val,
1760     struct configFileInfo * cfi)
1761    {
1762        struct singleLine * newLine = lineDup(tmplLine);
1763    
1764        if (val) {
1765     /* override the inherited value with our own.
1766     * This is a little weak because it only applies to elements[1]
1767     */
1768     if (newLine->numElements > 1)
1769        removeElement(newLine, 1);
1770     insertElement(newLine, val, 1, cfi);
1771    
1772     /* but try to keep the rootspec from the template... sigh */
1773     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1774        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1775        if (rootspec != NULL) {
1776     free(newLine->elements[1].item);
1777     newLine->elements[1].item =
1778        sdupprintf("%s%s", rootspec, val);
1779        }
1780     }
1781        }
1782    
1783        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1784          newLine->elements[0].item : "");
1785    
1786        if (!entry->lines) {
1787     /* first one on the list */
1788     entry->lines = newLine;
1789        } else if (prevLine) {
1790     /* add after prevLine */
1791     newLine->next = prevLine->next;
1792     prevLine->next = newLine;
1793        }
1794    
1795        return newLine;
1796    }
1797    
1798  /* val may be NULL */  /* val may be NULL */
1799  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1800       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1801       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1802       char * val) {       const char * val) {
1803      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1804      int i;      struct keywordTypes * kw;
1805        struct singleLine tmpl;
1806    
1807      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1808   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1809      if (type != LT_TITLE || !cfi->titleBracketed)       */
1810          if (!cfi->keywords[i].key) abort();  
1811        if (type == LT_TITLE && cfi->titleBracketed) {
1812     /* we're doing a bracketed title (zipl) */
1813     tmpl.type = type;
1814     tmpl.numElements = 1;
1815     tmpl.elements = alloca(sizeof(*tmpl.elements));
1816     tmpl.elements[0].item = alloca(strlen(val)+3);
1817     sprintf(tmpl.elements[0].item, "[%s]", val);
1818     tmpl.elements[0].indent = "";
1819     val = NULL;
1820        } else {
1821     kw = getKeywordByType(type, cfi);
1822     if (!kw) abort();
1823     tmpl.type = type;
1824     tmpl.numElements = val ? 2 : 1;
1825     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1826     tmpl.elements[0].item = kw->key;
1827     tmpl.elements[0].indent = alloca(2);
1828     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1829     if (val) {
1830        tmpl.elements[1].item = (char *)val;
1831        tmpl.elements[1].indent = "";
1832     }
1833        }
1834    
1835      /* 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
1836         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1837         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
1838         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1839         differently from the rest) */         differently from the rest) */
1840      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1841   line = entry->lines;   if (line->numElements) prev = line;
1842   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1843   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;  
1844      }      }
1845    
1846      if (type != LT_TITLE || !cfi->titleBracketed) {      if (prev == entry->lines)
1847          line->type = type;   tmpl.indent = defaultIndent ?: "";
1848          line->numElements = val ? 2 : 1;      else
1849          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("");  
     }  
1850    
1851      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1852  }  }
1853    
1854  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 1873  void removeLine(struct singleEntry * ent
1873      free(line);      free(line);
1874  }  }
1875    
1876    static void insertElement(struct singleLine * line,
1877      const char * item, int insertHere,
1878      struct configFileInfo * cfi)
1879    {
1880        struct keywordTypes * kw;
1881        char indent[2] = "";
1882    
1883        /* sanity check */
1884        if (insertHere > line->numElements) {
1885     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
1886      insertHere, line->numElements);
1887     insertHere = line->numElements;
1888        }
1889    
1890        line->elements = realloc(line->elements, (line->numElements + 1) *
1891         sizeof(*line->elements));
1892        memmove(&line->elements[insertHere+1],
1893        &line->elements[insertHere],
1894        (line->numElements - insertHere) *
1895        sizeof(*line->elements));
1896        line->elements[insertHere].item = strdup(item);
1897    
1898        kw = getKeywordByType(line->type, cfi);
1899    
1900        if (line->numElements == 0) {
1901     indent[0] = '\0';
1902        } else if (insertHere == 0) {
1903     indent[0] = kw->nextChar;
1904        } else if (kw->separatorChar != '\0') {
1905     indent[0] = kw->separatorChar;
1906        } else {
1907     indent[0] = ' ';
1908        }
1909    
1910        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
1911     /* move the end-of-line forward */
1912     line->elements[insertHere].indent =
1913        line->elements[insertHere-1].indent;
1914     line->elements[insertHere-1].indent = strdup(indent);
1915        } else {
1916     line->elements[insertHere].indent = strdup(indent);
1917        }
1918    
1919        line->numElements++;
1920    
1921        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
1922          line->elements[0].item,
1923          line->elements[insertHere].item,
1924          line->elements[insertHere].indent,
1925          insertHere);
1926    }
1927    
1928    static void removeElement(struct singleLine * line, int removeHere) {
1929        int i;
1930    
1931        /* sanity check */
1932        if (removeHere >= line->numElements) return;
1933    
1934        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
1935          removeHere, line->elements[removeHere].item);
1936    
1937        free(line->elements[removeHere].item);
1938    
1939        if (removeHere > 1) {
1940     /* previous argument gets this argument's post-indentation */
1941     free(line->elements[removeHere-1].indent);
1942     line->elements[removeHere-1].indent =
1943        line->elements[removeHere].indent;
1944        } else {
1945     free(line->elements[removeHere].indent);
1946        }
1947    
1948        /* now collapse the array, but don't bother to realloc smaller */
1949        for (i = removeHere; i < line->numElements - 1; i++)
1950     line->elements[i] = line->elements[i + 1];
1951    
1952        line->numElements--;
1953    }
1954    
1955  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
1956      char * first, * second;      char * first, * second;
1957      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 1974  int updateActualImage(struct grubConfig
1974      struct singleEntry * entry;      struct singleEntry * entry;
1975      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
1976      int index = 0;      int index = 0;
1977      int i, j, k;      int i, k;
1978      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
1979      const char ** arg;      const char ** arg;
1980      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
1981      int firstElement;      int firstElement;
1982      int *usedElements, *usedArgs;      int *usedElements, *usedArgs;
1983        int doreplace;
1984    
1985      if (!image) return 0;      if (!image) return 0;
1986    
# Line 1609  int updateActualImage(struct grubConfig Line 2007  int updateActualImage(struct grubConfig
2007   }   }
2008      }      }
2009    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2010    
2011      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2012   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2013    
2014      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2015   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2016    
2017      if (cfg->cfi->keywords[i].key)      for (k = 0, arg = newArgs; *arg; arg++, k++) ;
2018   useRoot = 1;      usedArgs = calloc(k, sizeof(*usedArgs));
2019    
2020      k = 0;      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2021      for (arg = newArgs; *arg; arg++)  
2022          k++;   if (multibootArgs && !entry->multiboot)
2023      usedArgs = calloc(k, sizeof(int));      continue;
2024    
2025     /* Determine where to put the args.  If this config supports
2026     * LT_KERNELARGS, use that.  Otherwise use
2027     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2028     */
2029     if (useKernelArgs) {
2030        line = getLineByType(LT_KERNELARGS, entry->lines);
2031        if (!line) {
2032     /* no LT_KERNELARGS, need to add it */
2033     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2034           cfg->secondaryIndent, NULL);
2035        }
2036        firstElement = 1;
2037    
2038      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2039   index++;      line = getLineByType(LT_HYPER, entry->lines);
2040        if (!line) {
2041     /* a multiboot entry without LT_HYPER? */
2042     continue;
2043        }
2044        firstElement = 2;
2045    
2046   line = entry->lines;   } else {
2047   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2048   if (!line) continue;      if (!line) {
2049   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2050     continue;
2051          if (entry->multiboot && !multibootArgs) {      }
2052              /* 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;  
2053   }   }
2054    
2055   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2056      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2057      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2058     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2059        /* this is a multiboot entry, make sure there's
2060         * -- on the args line
2061         */
2062        for (i = firstElement; i < line->numElements; i++) {
2063     if (!strcmp(line->elements[i].item, "--"))
2064        break;
2065        }
2066        if (i == line->numElements) {
2067     /* assume all existing args are kernel args,
2068     * prepend -- to make it official
2069     */
2070     insertElement(line, "--", firstElement, cfg->cfi);
2071     i = firstElement;
2072        }
2073        if (!multibootArgs) {
2074     /* kernel args start after the -- */
2075     firstElement = i + 1;
2076        }
2077     } else if (cfg->cfi->mbConcatArgs) {
2078        /* this is a non-multiboot entry, remove hyper args */
2079        for (i = firstElement; i < line->numElements; i++) {
2080     if (!strcmp(line->elements[i].item, "--"))
2081        break;
2082        }
2083        if (i < line->numElements) {
2084     /* remove args up to -- */
2085     while (strcmp(line->elements[firstElement].item, "--"))
2086        removeElement(line, firstElement);
2087     /* remove -- */
2088     removeElement(line, firstElement);
2089        }
2090   }   }
2091    
2092          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2093    
2094          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2095   for (arg = newArgs; *arg; arg++) {              if (usedArgs[k]) continue;
2096              if (usedArgs[k]) {  
2097                  k++;      doreplace = 1;
                 continue;  
             }  
2098      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2099     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2100        !strcmp(line->elements[i].item, "--"))
2101     {
2102        /* reached the end of hyper args, insert here */
2103        doreplace = 0;
2104        break;  
2105     }
2106                  if (usedElements[i])                  if (usedElements[i])
2107                      continue;                      continue;
2108   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
# Line 1665  int updateActualImage(struct grubConfig Line 2111  int updateActualImage(struct grubConfig
2111      break;      break;
2112                  }                  }
2113              }              }
     chptr = strchr(*arg, '=');  
2114    
2115      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2116   /* replace */   /* direct replacement */
2117   free(line->elements[i].item);   free(line->elements[i].item);
2118   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("");  
  }  
2119    
2120   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2121   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2122      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2123   /* append */   if (rootLine) {
2124   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2125   (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(" ");  
2126   } else {   } else {
2127      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2128         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2129   }   }
2130        }
2131    
2132   line->numElements++;      else {
2133     /* insert/append */
2134     insertElement(line, *arg, i, cfg->cfi);
2135     usedElements = realloc(usedElements, line->numElements *
2136           sizeof(*usedElements));
2137     memmove(&usedElements[i + 1], &usedElements[i],
2138     line->numElements - i - 1);
2139     usedElements[i] = 1;
2140    
2141   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2142     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2143     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2144   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2145      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2146      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2147   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2148   }   }
2149      }      }
             k++;  
2150   }   }
2151    
2152          free(usedElements);          free(usedElements);
2153    
  /* 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? */  
2154   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2155      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2156   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2157        !strcmp(line->elements[i].item, "--"))
2158        /* reached the end of hyper args, stop here */
2159        break;
2160     if (!argMatch(line->elements[i].item, *arg)) {
2161        removeElement(line, i);
2162      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;  
2163   }   }
2164        }
2165   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2166        if (useRoot && !strncmp(*arg, "root=", 5)) {
2167   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2168      line->elements[j - 1] = line->elements[j];   if (rootLine)
2169        removeLine(entry, rootLine);
  line->numElements--;  
2170      }      }
2171   }   }
2172    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2203  int updateImage(struct grubConfig * cfg,
2203      return rc;      return rc;
2204  }  }
2205    
2206    int updateInitrd(struct grubConfig * cfg, const char * image,
2207                     const char * prefix, const char * initrd) {
2208        struct singleEntry * entry;
2209        struct singleLine * line, * kernelLine;
2210        int index = 0;
2211    
2212        if (!image) return 0;
2213    
2214        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2215            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2216            if (!kernelLine) continue;
2217    
2218            line = getLineByType(LT_INITRD, entry->lines);
2219            if (line)
2220                removeLine(entry, line);
2221            if (prefix) {
2222                int prefixLen = strlen(prefix);
2223                if (!strncmp(initrd, prefix, prefixLen))
2224                    initrd += prefixLen;
2225            }
2226            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2227            if (!line) return 1;
2228            break;
2229        }
2230    
2231        return 0;
2232    }
2233    
2234  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2235      int fd;      int fd;
2236      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2421  int checkForGrub(struct grubConfig * con
2421      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2422   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2423   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2424     close(fd);
2425     return 1;
2426        }
2427        close(fd);
2428    
2429        return checkDeviceBootloader(boot, bootSect);
2430    }
2431    
2432    int checkForExtLinux(struct grubConfig * config) {
2433        int fd;
2434        unsigned char bootSect[512];
2435        char * boot;
2436        char executable[] = "/boot/extlinux/extlinux";
2437    
2438        printf("entered: checkForExtLinux()\n");
2439    
2440        if (parseSysconfigGrub(NULL, &boot))
2441     return 0;
2442    
2443        /* assume grub is not installed -- not an error condition */
2444        if (!boot)
2445     return 0;
2446    
2447        fd = open(executable, O_RDONLY);
2448        if (fd < 0)
2449     /* this doesn't exist if grub hasn't been installed */
2450     return 0;
2451    
2452        if (read(fd, bootSect, 512) != 512) {
2453     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2454     executable, strerror(errno));
2455   return 1;   return 1;
2456      }      }
2457      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2470  static char * getRootSpecifier(char * st
2470      return rootspec;      return rootspec;
2471  }  }
2472    
2473    static char * getInitrdVal(struct grubConfig * config,
2474       const char * prefix, struct singleLine *tmplLine,
2475       const char * newKernelInitrd,
2476       char ** extraInitrds, int extraInitrdCount)
2477    {
2478        char *initrdVal, *end;
2479        int i;
2480        size_t totalSize;
2481        size_t prefixLen;
2482        char separatorChar;
2483    
2484        prefixLen = strlen(prefix);
2485        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2486    
2487        for (i = 0; i < extraInitrdCount; i++) {
2488     totalSize += sizeof(separatorChar);
2489     totalSize += strlen(extraInitrds[i]) - prefixLen;
2490        }
2491    
2492        initrdVal = end = malloc(totalSize);
2493    
2494        end = stpcpy (end, newKernelInitrd + prefixLen);
2495    
2496        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2497        for (i = 0; i < extraInitrdCount; i++) {
2498     const char *extraInitrd;
2499     int j;
2500    
2501     extraInitrd = extraInitrds[i] + prefixLen;
2502     /* Don't add entries that are already there */
2503     if (tmplLine != NULL) {
2504        for (j = 2; j < tmplLine->numElements; j++)
2505     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2506        break;
2507    
2508        if (j != tmplLine->numElements)
2509     continue;
2510     }
2511    
2512     *end++ = separatorChar;
2513     end = stpcpy(end, extraInitrd);
2514        }
2515    
2516        return initrdVal;
2517    }
2518    
2519  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2520           const char * prefix,           const char * prefix,
2521   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2522   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2523     char ** extraInitrds, int extraInitrdCount,
2524                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2525      struct singleEntry * new;      struct singleEntry * new;
2526      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2527      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2528      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2529    
2530      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2531    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2555  int addNewKernel(struct grubConfig * con
2555      config->entries = new;      config->entries = new;
2556    
2557      /* copy/update from the template */      /* copy/update from the template */
2558      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2559        if (newKernelInitrd)
2560     needs |= NEED_INITRD;
2561      if (newMBKernel) {      if (newMBKernel) {
2562          needs |= KERNEL_MB;          needs |= NEED_MB;
2563          new->multiboot = 1;          new->multiboot = 1;
2564      }      }
2565    
2566      if (template) {      if (template) {
2567   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2568      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2569      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2570   indent = tmplLine->indent;   {
2571        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2572    
2573      /* skip comments */      /* skip comments */
2574      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2575      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2576      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2577    
2578      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2579      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   tmplLine->numElements >= 2) {
2580     if (!template->multiboot && (needs & NEED_MB)) {
2581              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2582                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2583                  struct singleLine *l;       * hypervisor at the same time.
2584                  needs &= ~ KERNEL_MB;       */
2585        if (config->cfi->mbHyperFirst) {
2586                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2587                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2588                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2589                      newMBKernel + strlen(prefix));
2590                  tmplLine = lastLine;   /* set up for adding the kernel line */
2591                  if (!new->lines) {   free(tmplLine->indent);
2592                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2593                  } else {   needs &= ~NEED_MB;
2594                      newLine->next = l;      }
2595                      newLine = l;      if (needs & NEED_KERNEL) {
2596                  }   /* use addLineTmpl to preserve line elements,
2597                  continue;   * otherwise we could just call addLine.  Unfortunately
2598              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2599                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2600                  continue; /* don't need multiboot kernel here */   * change below.
2601              }   */
2602     struct keywordTypes * mbm_kw =
2603        getKeywordByType(LT_MBMODULE, config->cfi);
2604     if (mbm_kw) {
2605        tmplLine->type = LT_MBMODULE;
2606        free(tmplLine->elements[0].item);
2607        tmplLine->elements[0].item = strdup(mbm_kw->key);
2608     }
2609     newLine = addLineTmpl(new, tmplLine, newLine,
2610          newKernelPath + strlen(prefix), config->cfi);
2611     needs &= ~NEED_KERNEL;
2612        }
2613        if (needs & NEED_MB) { /* !mbHyperFirst */
2614     newLine = addLine(new, config->cfi, LT_HYPER,
2615      config->secondaryIndent,
2616      newMBKernel + strlen(prefix));
2617     needs &= ~NEED_MB;
2618        }
2619     } else if (needs & NEED_KERNEL) {
2620        newLine = addLineTmpl(new, tmplLine, newLine,
2621      newKernelPath + strlen(prefix), config->cfi);
2622        needs &= ~NEED_KERNEL;
2623     }
2624    
2625      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2626   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2627   new->lines = newLine;   if (needs & NEED_MB) {
2628      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2629   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2630   newLine = newLine->next;      needs &= ~NEED_MB;
2631      }   }
2632    
2633        } else if (tmplLine->type == LT_MBMODULE &&
2634           tmplLine->numElements >= 2) {
2635     if (new->multiboot) {
2636        if (needs & NEED_KERNEL) {
2637     newLine = addLineTmpl(new, tmplLine, newLine,
2638          newKernelPath +
2639          strlen(prefix), config->cfi);
2640     needs &= ~NEED_KERNEL;
2641        } else if (config->cfi->mbInitRdIsModule &&
2642           (needs & NEED_INITRD)) {
2643     char *initrdVal;
2644     initrdVal = getInitrdVal(config, prefix, tmplLine,
2645     newKernelInitrd, extraInitrds,
2646     extraInitrdCount);
2647     newLine = addLineTmpl(new, tmplLine, newLine,
2648          initrdVal, config->cfi);
2649     free(initrdVal);
2650     needs &= ~NEED_INITRD;
2651        }
2652     } else if (needs & NEED_KERNEL) {
2653        /* template is multi but new is not,
2654         * insert the kernel in the first module slot
2655         */
2656        tmplLine->type = LT_KERNEL;
2657        free(tmplLine->elements[0].item);
2658        tmplLine->elements[0].item =
2659     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2660        newLine = addLineTmpl(new, tmplLine, newLine,
2661      newKernelPath + strlen(prefix), config->cfi);
2662        needs &= ~NEED_KERNEL;
2663     } else if (needs & NEED_INITRD) {
2664        char *initrdVal;
2665        /* template is multi but new is not,
2666         * insert the initrd in the second module slot
2667         */
2668        tmplLine->type = LT_INITRD;
2669        free(tmplLine->elements[0].item);
2670        tmplLine->elements[0].item =
2671     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2672        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2673        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2674        free(initrdVal);
2675        needs &= ~NEED_INITRD;
2676     }
2677    
     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));  
                 }  
2678      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2679      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2680   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2681   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2682                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2683                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2684                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2685                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2686                  }       */
2687                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2688                  if (rootspec != NULL) {   char *initrdVal;
2689                      newLine->elements[1].item = sdupprintf("%s%s",  
2690                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2691                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2692                                                             strlen(prefix));    config->secondaryIndent,
2693                  } else {    initrdVal);
2694                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2695                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2696                  }      }
2697              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2698                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2699   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2700                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2701                      free(newLine->elements[0].item);      free(initrdVal);
2702                      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);  
2703   }   }
2704    
  newLine->elements[1].item = strdup(newKernelTitle);  
  newLine->elements[1].indent = strdup("");  
  newLine->numElements = 2;  
2705      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2706                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2707                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2708                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2709                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2710                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2711                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2712                                             newLine->numElements);     config->cfi->titleBracketed) {
2713        /* addLineTmpl doesn't handle titleBracketed */
2714                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2715                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2716                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2717                  newLine->numElements = 1;   }
2718              }  
2719        } else {
2720     /* pass through other lines from the template */
2721     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2722        }
2723   }   }
2724    
2725      } else {      } else {
2726   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2727      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2728     */
2729     switch (config->cfi->entrySeparator) {
2730        case LT_KERNEL:
2731     if (new->multiboot && config->cfi->mbHyperFirst) {
2732        /* fall through to LT_HYPER */
2733     } else {
2734        newLine = addLine(new, config->cfi, LT_KERNEL,
2735          config->primaryIndent,
2736          newKernelPath + strlen(prefix));
2737        needs &= ~NEED_KERNEL;
2738        break;
2739     }
2740    
2741        case LT_HYPER:
2742     newLine = addLine(new, config->cfi, LT_HYPER,
2743      config->primaryIndent,
2744      newMBKernel + strlen(prefix));
2745     needs &= ~NEED_MB;
2746   break;   break;
         }  
2747    
2748   switch (config->cfi->keywords[i].type) {      case LT_TITLE:
2749      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
2750       chptr = newKernelPath + strlen(prefix);   char * templabel;
2751       type = LT_KERNEL; break;   int x = 0, y = 0;
2752      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;  
2753       type = LT_TITLE; break;   templabel = strdup(newKernelTitle);
2754      default:       while( templabel[x]){
2755                  /* zipl strikes again */   if( templabel[x] == ' ' ){
2756                  if (config->cfi->titleBracketed) {   y = x;
2757                      needs &= ~KERNEL_TITLE;   while( templabel[y] ){
2758                      chptr = newKernelTitle;   templabel[y] = templabel[y+1];
2759                      type = LT_TITLE;   y++;
2760                      break;   }
2761                  } else {   }
2762                      abort();   x++;
2763                  }   }
2764   }   newLine = addLine(new, config->cfi, LT_TITLE,
2765      config->primaryIndent, templabel);
2766     free(templabel);
2767     }else{
2768     newLine = addLine(new, config->cfi, LT_TITLE,
2769      config->primaryIndent, newKernelTitle);
2770     }
2771     needs &= ~NEED_TITLE;
2772     break;
2773    
2774   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
2775   new->lines = newLine;   abort();
2776     }
2777      }      }
2778    
2779      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
2780          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
2781              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entrySeparator.
2782                                config->secondaryIndent,       */
2783                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
2784          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
2785              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
2786                                config->secondaryIndent,    newKernelTitle);
2787                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
2788          /* don't need to check for title as it's guaranteed to have been      }
2789           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
2790           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
2791          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
2792              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
2793                                config->secondaryIndent,   needs &= ~NEED_MB;
2794                                newKernelInitrd + strlen(prefix));      }
2795      } else {      if (needs & NEED_KERNEL) {
2796          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
2797              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
2798                                config->secondaryIndent,        config->cfi)) ?
2799                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
2800          if (needs & KERNEL_TITLE)    config->secondaryIndent,
2801              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
2802                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
2803                                newKernelTitle);      }
2804          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
2805              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
2806                                config->secondaryIndent,    config->secondaryIndent,
2807                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
2808     needs &= ~NEED_MB;
2809        }
2810        if (needs & NEED_INITRD) {
2811     char *initrdVal;
2812     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
2813     newLine = addLine(new, config->cfi,
2814      (new->multiboot && getKeywordByType(LT_MBMODULE,
2815          config->cfi)) ?
2816      LT_MBMODULE : LT_INITRD,
2817      config->secondaryIndent,
2818      initrdVal);
2819     free(initrdVal);
2820     needs &= ~NEED_INITRD;
2821        }
2822    
2823        if (needs) {
2824     printf(_("grubby: needs=%d, aborting\n"), needs);
2825     abort();
2826      }      }
2827    
2828      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 2831  int addNewKernel(struct grubConfig * con
2831      return 0;      return 0;
2832  }  }
2833    
2834    static void traceback(int signum)
2835    {
2836        void *array[40];
2837        size_t size;
2838    
2839        signal(SIGSEGV, SIG_DFL);
2840        memset(array, '\0', sizeof (array));
2841        size = backtrace(array, 40);
2842    
2843        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
2844                (unsigned long)size);
2845        backtrace_symbols_fd(array, size, STDERR_FILENO);
2846        exit(1);
2847    }
2848    
2849  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
2850      poptContext optCon;      poptContext optCon;
2851      char * grubConfig = NULL;      char * grubConfig = NULL;
# Line 2283  int main(int argc, const char ** argv) { Line 2855  int main(int argc, const char ** argv) {
2855      int badImageOkay = 0;      int badImageOkay = 0;
2856      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
2857      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
2858        int configureExtLinux = 0;
2859      int bootloaderProbe = 0;      int bootloaderProbe = 0;
2860        int extraInitrdCount = 0;
2861      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
2862      char * newKernelPath = NULL;      char * newKernelPath = NULL;
2863      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 2873  int main(int argc, const char ** argv) {
2873      char * defaultKernel = NULL;      char * defaultKernel = NULL;
2874      char * removeArgs = NULL;      char * removeArgs = NULL;
2875      char * kernelInfo = NULL;      char * kernelInfo = NULL;
2876        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
2877      const char * chptr = NULL;      const char * chptr = NULL;
2878      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
2879      struct grubConfig * config;      struct grubConfig * config;
# Line 2339  int main(int argc, const char ** argv) { Line 2914  int main(int argc, const char ** argv) {
2914      _("display the path of the default kernel") },      _("display the path of the default kernel") },
2915   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
2916      _("configure elilo bootloader") },      _("configure elilo bootloader") },
2917     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
2918        _("configure extlinux bootloader (from syslinux)") },
2919   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
2920      _("configure grub bootloader") },      _("configure grub bootloader") },
2921   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
# Line 2346  int main(int argc, const char ** argv) { Line 2923  int main(int argc, const char ** argv) {
2923      _("kernel-path") },      _("kernel-path") },
2924   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
2925      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
2926     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
2927        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
2928   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
2929      _("configure lilo bootloader") },      _("configure lilo bootloader") },
2930   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 2961  int main(int argc, const char ** argv) {
2961   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
2962      };      };
2963    
2964        useextlinuxmenu=0;
2965    
2966        signal(SIGSEGV, traceback);
2967    
2968      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
2969      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
2970    
# Line 2391  int main(int argc, const char ** argv) { Line 2974  int main(int argc, const char ** argv) {
2974      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
2975      exit(0);      exit(0);
2976      break;      break;
2977      case 'i':
2978        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
2979         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
2980        } else {
2981     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
2982     return 1;
2983        }
2984        break;
2985   }   }
2986      }      }
2987    
# Line 2407  int main(int argc, const char ** argv) { Line 2998  int main(int argc, const char ** argv) {
2998      }      }
2999    
3000      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub + configureELilo +
3001   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3002     configureExtLinux ) > 1) {
3003   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3004   return 1;   return 1;
3005      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
# Line 2426  int main(int argc, const char ** argv) { Line 3018  int main(int argc, const char ** argv) {
3018          cfi = &siloConfigType;          cfi = &siloConfigType;
3019      } else if (configureZipl) {      } else if (configureZipl) {
3020          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3021        } else if (configureExtLinux) {
3022     cfi = &extlinuxConfigType;
3023     useextlinuxmenu=1;
3024      }      }
3025    
3026      if (!cfi) {      if (!cfi) {
# Line 2465  int main(int argc, const char ** argv) { Line 3060  int main(int argc, const char ** argv) {
3060      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3061   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3062   return 1;   return 1;
3063      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3064    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3065    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3066   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3067   return 1;   return 1;
3068      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3115  int main(int argc, const char ** argv) {
3115   bootPrefix = "";   bootPrefix = "";
3116      }      }
3117    
3118        if (!cfi->mbAllowExtraInitRds &&
3119     extraInitrdCount > 0) {
3120     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3121     return 1;
3122        }
3123    
3124      if (bootloaderProbe) {      if (bootloaderProbe) {
3125   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, erc = 0;
3126   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3127    
3128   if (!access(grubConfigType.defaultConfig, F_OK)) {   if (!access(grubConfigType.defaultConfig, F_OK)) {
# Line 2540  int main(int argc, const char ** argv) { Line 3141  int main(int argc, const char ** argv) {
3141   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3142   }   }
3143    
3144     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3145        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3146        if (!lconfig)
3147     erc = 1;
3148        else
3149     erc = checkForExtLinux(lconfig);
3150     }
3151    
3152   if (lrc == 1 || grc == 1) return 1;   if (lrc == 1 || grc == 1) return 1;
3153    
3154   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3155   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3156     if (erc == 2) printf("extlinux\n");
3157    
3158   return 0;   return 0;
3159      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3171  int main(int argc, const char ** argv) {
3171   if (!entry) return 0;   if (!entry) return 0;
3172   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3173    
3174   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3175   if (!line) return 0;   if (!line) return 0;
3176    
3177          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2585  int main(int argc, const char ** argv) { Line 3194  int main(int argc, const char ** argv) {
3194      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3195      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3196                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3197        if (updateKernelPath && newKernelInitrd) {
3198                if (updateInitrd(config, updateKernelPath, bootPrefix,
3199                                 newKernelInitrd)) return 1;
3200        }
3201      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3202                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3203                         extraInitrds, extraInitrdCount,
3204                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3205            
3206    

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