Magellan Linux

Diff of /tags/grubby-8_40_20170627/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 1156 by niro, Tue Sep 14 19:47:52 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;
  /* check which device has this label */  
  dev = get_spec_by_volume_label(dev, &i, &i);  
  if (!dev) return 0;  
     }  
1291    
1292      if (*dev == '/') {      rootdev = findDiskForRoot();
1293   if (stat(dev, &sb))      if (!rootdev)
1294      return 0;   return 0;
1295      } else {  
1296   sb.st_rdev = strtol(dev, &end, 16);  
1297   if (*end) return 0;      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1298     free(rootdev);
1299            return 0;
1300      }      }
     stat("/", &sb2);  
1301    
1302      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1303    
1304      return 1;      return 1;
1305  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1343  struct singleEntry * findEntryByPath(str
1343   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1344   if (!entry) return NULL;   if (!entry) return NULL;
1345    
1346   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1347   if (!line) return NULL;   if (!line) return NULL;
1348    
1349   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1385  struct singleEntry * findEntryByPath(str
1385      kernel += 6;      kernel += 6;
1386   }   }
1387    
1388   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1389      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1390    
1391        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1392    
1393      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1394                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1395          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1396                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1397                              kernel + strlen(prefix)))       checkType, line);
1398                      break;   if (!line) break;  /* not found in this entry */
1399              }  
1400                 if (line && line->numElements >= 2) {
1401              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1402              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1403                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1404                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1405                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1406                      if (!strcmp(line->elements[1].item  +   }
1407                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1408    
1409      i++;      /* make sure this entry has a kernel identifier; this skips
1410         * non-Linux boot entries (could find netbsd etc, though, which is
1411         * unfortunate)
1412         */
1413        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1414     break; /* found 'im! */
1415   }   }
1416    
1417   if (index) *index = i;   if (index) *index = i;
1418      }      }
1419    
     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);  
     }  
   
1420      return entry;      return entry;
1421  }  }
1422    
# Line 1286  void displayEntry(struct singleEntry * e Line 1581  void displayEntry(struct singleEntry * e
1581      char * root = NULL;      char * root = NULL;
1582      int i;      int i;
1583    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1584      printf("index=%d\n", index);      printf("index=%d\n", index);
1585    
1586        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1587        if (!line) {
1588            printf("non linux entry\n");
1589            return;
1590        }
1591    
1592      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1593    
1594      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1606  void displayEntry(struct singleEntry * e
1606   }   }
1607   printf("\"\n");   printf("\"\n");
1608      } else {      } else {
1609   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1610   if (line) {   if (line) {
1611      char * s;      char * s;
1612    
# Line 1334  void displayEntry(struct singleEntry * e Line 1630  void displayEntry(struct singleEntry * e
1630      }      }
1631    
1632      if (!root) {      if (!root) {
1633   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1634   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1635      root=line->elements[1].item;      root=line->elements[1].item;
1636      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1645  void displayEntry(struct singleEntry * e
1645   printf("root=%s\n", s);   printf("root=%s\n", s);
1646      }      }
1647    
1648      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1649    
1650      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1651   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1662  int parseSysconfigGrub(int * lbaPtr, cha
1662      char * start;      char * start;
1663      char * param;      char * param;
1664    
1665      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1666      if (!in) return 1;      if (!in) return 1;
1667    
1668      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1724  int displayInfo(struct grubConfig * conf
1724   return 1;   return 1;
1725      }      }
1726    
1727      /* 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
1728         be a better way */         be a better way */
1729      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1730   dumpSysconfigGrub();   dumpSysconfigGrub();
1731      } else {      } else {
1732   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1733   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1734      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1735   }   }
1736    
1737   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1738   if (line) printf("lba\n");   if (line) printf("lba\n");
1739      }      }
1740    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1749  int displayInfo(struct grubConfig * conf
1749      return 0;      return 0;
1750  }  }
1751    
1752    struct singleLine * addLineTmpl(struct singleEntry * entry,
1753     struct singleLine * tmplLine,
1754     struct singleLine * prevLine,
1755     const char * val,
1756     struct configFileInfo * cfi)
1757    {
1758        struct singleLine * newLine = lineDup(tmplLine);
1759    
1760        if (val) {
1761     /* override the inherited value with our own.
1762     * This is a little weak because it only applies to elements[1]
1763     */
1764     if (newLine->numElements > 1)
1765        removeElement(newLine, 1);
1766     insertElement(newLine, val, 1, cfi);
1767    
1768     /* but try to keep the rootspec from the template... sigh */
1769     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1770        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1771        if (rootspec != NULL) {
1772     free(newLine->elements[1].item);
1773     newLine->elements[1].item =
1774        sdupprintf("%s%s", rootspec, val);
1775        }
1776     }
1777        }
1778    
1779        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1780          newLine->elements[0].item : "");
1781    
1782        if (!entry->lines) {
1783     /* first one on the list */
1784     entry->lines = newLine;
1785        } else if (prevLine) {
1786     /* add after prevLine */
1787     newLine->next = prevLine->next;
1788     prevLine->next = newLine;
1789        }
1790    
1791        return newLine;
1792    }
1793    
1794  /* val may be NULL */  /* val may be NULL */
1795  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1796       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1797       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1798       char * val) {       const char * val) {
1799      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1800      int i;      struct keywordTypes * kw;
1801        struct singleLine tmpl;
1802    
1803      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1804   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1805      if (type != LT_TITLE || !cfi->titleBracketed)       */
1806          if (!cfi->keywords[i].key) abort();  
1807        if (type == LT_TITLE && cfi->titleBracketed) {
1808     /* we're doing a bracketed title (zipl) */
1809     tmpl.type = type;
1810     tmpl.numElements = 1;
1811     tmpl.elements = alloca(sizeof(*tmpl.elements));
1812     tmpl.elements[0].item = alloca(strlen(val)+3);
1813     sprintf(tmpl.elements[0].item, "[%s]", val);
1814     tmpl.elements[0].indent = "";
1815     val = NULL;
1816        } else {
1817     kw = getKeywordByType(type, cfi);
1818     if (!kw) abort();
1819     tmpl.type = type;
1820     tmpl.numElements = val ? 2 : 1;
1821     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1822     tmpl.elements[0].item = kw->key;
1823     tmpl.elements[0].indent = alloca(2);
1824     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1825     if (val) {
1826        tmpl.elements[1].item = (char *)val;
1827        tmpl.elements[1].indent = "";
1828     }
1829        }
1830    
1831      /* 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
1832         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1833         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
1834         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1835         differently from the rest) */         differently from the rest) */
1836      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1837   line = entry->lines;   if (line->numElements) prev = line;
1838   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1839   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;  
1840      }      }
1841    
1842      if (type != LT_TITLE || !cfi->titleBracketed) {      if (prev == entry->lines)
1843          line->type = type;   tmpl.indent = defaultIndent ?: "";
1844          line->numElements = val ? 2 : 1;      else
1845          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("");  
     }  
1846    
1847      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1848  }  }
1849    
1850  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 1869  void removeLine(struct singleEntry * ent
1869      free(line);      free(line);
1870  }  }
1871    
1872    static void insertElement(struct singleLine * line,
1873      const char * item, int insertHere,
1874      struct configFileInfo * cfi)
1875    {
1876        struct keywordTypes * kw;
1877        char indent[2] = "";
1878    
1879        /* sanity check */
1880        if (insertHere > line->numElements) {
1881     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
1882      insertHere, line->numElements);
1883     insertHere = line->numElements;
1884        }
1885    
1886        line->elements = realloc(line->elements, (line->numElements + 1) *
1887         sizeof(*line->elements));
1888        memmove(&line->elements[insertHere+1],
1889        &line->elements[insertHere],
1890        (line->numElements - insertHere) *
1891        sizeof(*line->elements));
1892        line->elements[insertHere].item = strdup(item);
1893    
1894        kw = getKeywordByType(line->type, cfi);
1895    
1896        if (line->numElements == 0) {
1897     indent[0] = '\0';
1898        } else if (insertHere == 0) {
1899     indent[0] = kw->nextChar;
1900        } else if (kw->separatorChar != '\0') {
1901     indent[0] = kw->separatorChar;
1902        } else {
1903     indent[0] = ' ';
1904        }
1905    
1906        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
1907     /* move the end-of-line forward */
1908     line->elements[insertHere].indent =
1909        line->elements[insertHere-1].indent;
1910     line->elements[insertHere-1].indent = strdup(indent);
1911        } else {
1912     line->elements[insertHere].indent = strdup(indent);
1913        }
1914    
1915        line->numElements++;
1916    
1917        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
1918          line->elements[0].item,
1919          line->elements[insertHere].item,
1920          line->elements[insertHere].indent,
1921          insertHere);
1922    }
1923    
1924    static void removeElement(struct singleLine * line, int removeHere) {
1925        int i;
1926    
1927        /* sanity check */
1928        if (removeHere >= line->numElements) return;
1929    
1930        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
1931          removeHere, line->elements[removeHere].item);
1932    
1933        free(line->elements[removeHere].item);
1934    
1935        if (removeHere > 1) {
1936     /* previous argument gets this argument's post-indentation */
1937     free(line->elements[removeHere-1].indent);
1938     line->elements[removeHere-1].indent =
1939        line->elements[removeHere].indent;
1940        } else {
1941     free(line->elements[removeHere].indent);
1942        }
1943    
1944        /* now collapse the array, but don't bother to realloc smaller */
1945        for (i = removeHere; i < line->numElements - 1; i++)
1946     line->elements[i] = line->elements[i + 1];
1947    
1948        line->numElements--;
1949    }
1950    
1951  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
1952      char * first, * second;      char * first, * second;
1953      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 1970  int updateActualImage(struct grubConfig
1970      struct singleEntry * entry;      struct singleEntry * entry;
1971      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
1972      int index = 0;      int index = 0;
1973      int i, j, k;      int i, k;
1974      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
1975      const char ** arg;      const char ** arg;
1976      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
1977      int firstElement;      int firstElement;
1978      int *usedElements, *usedArgs;      int *usedElements, *usedArgs;
1979        int doreplace;
1980    
1981      if (!image) return 0;      if (!image) return 0;
1982    
# Line 1609  int updateActualImage(struct grubConfig Line 2003  int updateActualImage(struct grubConfig
2003   }   }
2004      }      }
2005    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2006    
2007      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2008   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2009    
2010      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2011   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2012    
2013      if (cfg->cfi->keywords[i].key)      for (k = 0, arg = newArgs; *arg; arg++, k++) ;
2014   useRoot = 1;      usedArgs = calloc(k, sizeof(*usedArgs));
2015    
2016      k = 0;      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2017      for (arg = newArgs; *arg; arg++)  
2018          k++;   if (multibootArgs && !entry->multiboot)
2019      usedArgs = calloc(k, sizeof(int));      continue;
2020    
2021     /* Determine where to put the args.  If this config supports
2022     * LT_KERNELARGS, use that.  Otherwise use
2023     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2024     */
2025     if (useKernelArgs) {
2026        line = getLineByType(LT_KERNELARGS, entry->lines);
2027        if (!line) {
2028     /* no LT_KERNELARGS, need to add it */
2029     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2030           cfg->secondaryIndent, NULL);
2031        }
2032        firstElement = 1;
2033    
2034      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2035   index++;      line = getLineByType(LT_HYPER, entry->lines);
2036        if (!line) {
2037     /* a multiboot entry without LT_HYPER? */
2038     continue;
2039        }
2040        firstElement = 2;
2041    
2042   line = entry->lines;   } else {
2043   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2044   if (!line) continue;      if (!line) {
2045   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2046     continue;
2047          if (entry->multiboot && !multibootArgs) {      }
2048              /* 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;  
2049   }   }
2050    
2051   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2052      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2053      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2054     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2055        /* this is a multiboot entry, make sure there's
2056         * -- on the args line
2057         */
2058        for (i = firstElement; i < line->numElements; i++) {
2059     if (!strcmp(line->elements[i].item, "--"))
2060        break;
2061        }
2062        if (i == line->numElements) {
2063     /* assume all existing args are kernel args,
2064     * prepend -- to make it official
2065     */
2066     insertElement(line, "--", firstElement, cfg->cfi);
2067     i = firstElement;
2068        }
2069        if (!multibootArgs) {
2070     /* kernel args start after the -- */
2071     firstElement = i + 1;
2072        }
2073     } else if (cfg->cfi->mbConcatArgs) {
2074        /* this is a non-multiboot entry, remove hyper args */
2075        for (i = firstElement; i < line->numElements; i++) {
2076     if (!strcmp(line->elements[i].item, "--"))
2077        break;
2078        }
2079        if (i < line->numElements) {
2080     /* remove args up to -- */
2081     while (strcmp(line->elements[firstElement].item, "--"))
2082        removeElement(line, firstElement);
2083     /* remove -- */
2084     removeElement(line, firstElement);
2085        }
2086   }   }
2087    
2088          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2089    
2090          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2091   for (arg = newArgs; *arg; arg++) {              if (usedArgs[k]) continue;
2092              if (usedArgs[k]) {  
2093                  k++;      doreplace = 1;
                 continue;  
             }  
2094      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2095     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2096        !strcmp(line->elements[i].item, "--"))
2097     {
2098        /* reached the end of hyper args, insert here */
2099        doreplace = 0;
2100        break;  
2101     }
2102                  if (usedElements[i])                  if (usedElements[i])
2103                      continue;                      continue;
2104   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
# Line 1665  int updateActualImage(struct grubConfig Line 2107  int updateActualImage(struct grubConfig
2107      break;      break;
2108                  }                  }
2109              }              }
     chptr = strchr(*arg, '=');  
2110    
2111      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2112   /* replace */   /* direct replacement */
2113   free(line->elements[i].item);   free(line->elements[i].item);
2114   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("");  
  }  
2115    
2116   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2117   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2118      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2119   /* append */   if (rootLine) {
2120   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2121   (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(" ");  
2122   } else {   } else {
2123      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2124         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2125   }   }
2126        }
2127    
2128   line->numElements++;      else {
2129     /* insert/append */
2130     insertElement(line, *arg, i, cfg->cfi);
2131     usedElements = realloc(usedElements, line->numElements *
2132           sizeof(*usedElements));
2133     memmove(&usedElements[i + 1], &usedElements[i],
2134     line->numElements - i - 1);
2135     usedElements[i] = 1;
2136    
2137   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2138     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2139     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2140   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2141      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2142      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2143   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2144   }   }
2145      }      }
             k++;  
2146   }   }
2147    
2148          free(usedElements);          free(usedElements);
2149    
  /* 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? */  
2150   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2151      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2152   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2153        !strcmp(line->elements[i].item, "--"))
2154        /* reached the end of hyper args, stop here */
2155        break;
2156     if (!argMatch(line->elements[i].item, *arg)) {
2157        removeElement(line, i);
2158      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;  
2159   }   }
2160        }
2161   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2162        if (useRoot && !strncmp(*arg, "root=", 5)) {
2163   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2164      line->elements[j - 1] = line->elements[j];   if (rootLine)
2165        removeLine(entry, rootLine);
  line->numElements--;  
2166      }      }
2167   }   }
2168    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2199  int updateImage(struct grubConfig * cfg,
2199      return rc;      return rc;
2200  }  }
2201    
2202    int updateInitrd(struct grubConfig * cfg, const char * image,
2203                     const char * prefix, const char * initrd) {
2204        struct singleEntry * entry;
2205        struct singleLine * line, * kernelLine;
2206        int index = 0;
2207    
2208        if (!image) return 0;
2209    
2210        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2211            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2212            if (!kernelLine) continue;
2213    
2214            line = getLineByType(LT_INITRD, entry->lines);
2215            if (line)
2216                removeLine(entry, line);
2217            if (prefix) {
2218                int prefixLen = strlen(prefix);
2219                if (!strncmp(initrd, prefix, prefixLen))
2220                    initrd += prefixLen;
2221            }
2222            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2223            if (!line) return 1;
2224            break;
2225        }
2226    
2227        return 0;
2228    }
2229    
2230  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2231      int fd;      int fd;
2232      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2417  int checkForGrub(struct grubConfig * con
2417      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2418   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2419   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2420     close(fd);
2421     return 1;
2422        }
2423        close(fd);
2424    
2425        return checkDeviceBootloader(boot, bootSect);
2426    }
2427    
2428    int checkForExtLinux(struct grubConfig * config) {
2429        int fd;
2430        unsigned char bootSect[512];
2431        char * boot;
2432        char executable[] = "/boot/extlinux/extlinux";
2433    
2434        printf("entered: checkForExtLinux()\n");
2435    
2436        if (parseSysconfigGrub(NULL, &boot))
2437     return 0;
2438    
2439        /* assume grub is not installed -- not an error condition */
2440        if (!boot)
2441     return 0;
2442    
2443        fd = open(executable, O_RDONLY);
2444        if (fd < 0)
2445     /* this doesn't exist if grub hasn't been installed */
2446     return 0;
2447    
2448        if (read(fd, bootSect, 512) != 512) {
2449     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2450     executable, strerror(errno));
2451   return 1;   return 1;
2452      }      }
2453      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2466  static char * getRootSpecifier(char * st
2466      return rootspec;      return rootspec;
2467  }  }
2468    
2469    static char * getInitrdVal(struct grubConfig * config,
2470       const char * prefix, struct singleLine *tmplLine,
2471       const char * newKernelInitrd,
2472       char ** extraInitrds, int extraInitrdCount)
2473    {
2474        char *initrdVal, *end;
2475        int i;
2476        size_t totalSize;
2477        size_t prefixLen;
2478        char separatorChar;
2479    
2480        prefixLen = strlen(prefix);
2481        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2482    
2483        for (i = 0; i < extraInitrdCount; i++) {
2484     totalSize += sizeof(separatorChar);
2485     totalSize += strlen(extraInitrds[i]) - prefixLen;
2486        }
2487    
2488        initrdVal = end = malloc(totalSize);
2489    
2490        end = stpcpy (end, newKernelInitrd + prefixLen);
2491    
2492        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2493        for (i = 0; i < extraInitrdCount; i++) {
2494     const char *extraInitrd;
2495     int j;
2496    
2497     extraInitrd = extraInitrds[i] + prefixLen;
2498     /* Don't add entries that are already there */
2499     if (tmplLine != NULL) {
2500        for (j = 2; j < tmplLine->numElements; j++)
2501     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2502        break;
2503    
2504        if (j != tmplLine->numElements)
2505     continue;
2506     }
2507    
2508     *end++ = separatorChar;
2509     end = stpcpy(end, extraInitrd);
2510        }
2511    
2512        return initrdVal;
2513    }
2514    
2515  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2516           const char * prefix,           const char * prefix,
2517   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2518   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2519     char ** extraInitrds, int extraInitrdCount,
2520                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2521      struct singleEntry * new;      struct singleEntry * new;
2522      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2523      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2524      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2525    
2526      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2527    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2551  int addNewKernel(struct grubConfig * con
2551      config->entries = new;      config->entries = new;
2552    
2553      /* copy/update from the template */      /* copy/update from the template */
2554      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2555        if (newKernelInitrd)
2556     needs |= NEED_INITRD;
2557      if (newMBKernel) {      if (newMBKernel) {
2558          needs |= KERNEL_MB;          needs |= NEED_MB;
2559          new->multiboot = 1;          new->multiboot = 1;
2560      }      }
2561    
2562      if (template) {      if (template) {
2563   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2564      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2565      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2566   indent = tmplLine->indent;   {
2567        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2568    
2569      /* skip comments */      /* skip comments */
2570      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2571      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2572      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2573    
2574      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2575      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   tmplLine->numElements >= 2) {
2576     if (!template->multiboot && (needs & NEED_MB)) {
2577              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2578                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2579                  struct singleLine *l;       * hypervisor at the same time.
2580                  needs &= ~ KERNEL_MB;       */
2581        if (config->cfi->mbHyperFirst) {
2582                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2583                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2584                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2585                      newMBKernel + strlen(prefix));
2586                  tmplLine = lastLine;   /* set up for adding the kernel line */
2587                  if (!new->lines) {   free(tmplLine->indent);
2588                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2589                  } else {   needs &= ~NEED_MB;
2590                      newLine->next = l;      }
2591                      newLine = l;      if (needs & NEED_KERNEL) {
2592                  }   /* use addLineTmpl to preserve line elements,
2593                  continue;   * otherwise we could just call addLine.  Unfortunately
2594              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2595                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2596                  continue; /* don't need multiboot kernel here */   * change below.
2597              }   */
2598     struct keywordTypes * mbm_kw =
2599        getKeywordByType(LT_MBMODULE, config->cfi);
2600     if (mbm_kw) {
2601        tmplLine->type = LT_MBMODULE;
2602        free(tmplLine->elements[0].item);
2603        tmplLine->elements[0].item = strdup(mbm_kw->key);
2604     }
2605     newLine = addLineTmpl(new, tmplLine, newLine,
2606          newKernelPath + strlen(prefix), config->cfi);
2607     needs &= ~NEED_KERNEL;
2608        }
2609        if (needs & NEED_MB) { /* !mbHyperFirst */
2610     newLine = addLine(new, config->cfi, LT_HYPER,
2611      config->secondaryIndent,
2612      newMBKernel + strlen(prefix));
2613     needs &= ~NEED_MB;
2614        }
2615     } else if (needs & NEED_KERNEL) {
2616        newLine = addLineTmpl(new, tmplLine, newLine,
2617      newKernelPath + strlen(prefix), config->cfi);
2618        needs &= ~NEED_KERNEL;
2619     }
2620    
2621      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2622   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2623   new->lines = newLine;   if (needs & NEED_MB) {
2624      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2625   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2626   newLine = newLine->next;      needs &= ~NEED_MB;
2627      }   }
2628    
2629        } else if (tmplLine->type == LT_MBMODULE &&
2630           tmplLine->numElements >= 2) {
2631     if (new->multiboot) {
2632        if (needs & NEED_KERNEL) {
2633     newLine = addLineTmpl(new, tmplLine, newLine,
2634          newKernelPath +
2635          strlen(prefix), config->cfi);
2636     needs &= ~NEED_KERNEL;
2637        } else if (config->cfi->mbInitRdIsModule &&
2638           (needs & NEED_INITRD)) {
2639     char *initrdVal;
2640     initrdVal = getInitrdVal(config, prefix, tmplLine,
2641     newKernelInitrd, extraInitrds,
2642     extraInitrdCount);
2643     newLine = addLineTmpl(new, tmplLine, newLine,
2644          initrdVal, config->cfi);
2645     free(initrdVal);
2646     needs &= ~NEED_INITRD;
2647        }
2648     } else if (needs & NEED_KERNEL) {
2649        /* template is multi but new is not,
2650         * insert the kernel in the first module slot
2651         */
2652        tmplLine->type = LT_KERNEL;
2653        free(tmplLine->elements[0].item);
2654        tmplLine->elements[0].item =
2655     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2656        newLine = addLineTmpl(new, tmplLine, newLine,
2657      newKernelPath + strlen(prefix), config->cfi);
2658        needs &= ~NEED_KERNEL;
2659     } else if (needs & NEED_INITRD) {
2660        char *initrdVal;
2661        /* template is multi but new is not,
2662         * insert the initrd in the second module slot
2663         */
2664        tmplLine->type = LT_INITRD;
2665        free(tmplLine->elements[0].item);
2666        tmplLine->elements[0].item =
2667     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2668        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2669        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2670        free(initrdVal);
2671        needs &= ~NEED_INITRD;
2672     }
2673    
     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));  
                 }  
2674      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2675      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2676   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2677   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2678                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2679                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2680                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2681                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2682                  }       */
2683                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2684                  if (rootspec != NULL) {   char *initrdVal;
2685                      newLine->elements[1].item = sdupprintf("%s%s",  
2686                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2687                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2688                                                             strlen(prefix));    config->secondaryIndent,
2689                  } else {    initrdVal);
2690                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2691                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2692                  }      }
2693              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2694                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2695   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2696                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2697                      free(newLine->elements[0].item);      free(initrdVal);
2698                      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);  
2699   }   }
2700    
  newLine->elements[1].item = strdup(newKernelTitle);  
  newLine->elements[1].indent = strdup("");  
  newLine->numElements = 2;  
2701      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2702                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2703                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2704                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2705                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2706                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2707                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2708                                             newLine->numElements);     config->cfi->titleBracketed) {
2709        /* addLineTmpl doesn't handle titleBracketed */
2710                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2711                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2712                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2713                  newLine->numElements = 1;   }
2714              }  
2715        } else {
2716     /* pass through other lines from the template */
2717     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2718        }
2719   }   }
2720    
2721      } else {      } else {
2722   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2723      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2724     */
2725     switch (config->cfi->entrySeparator) {
2726        case LT_KERNEL:
2727     if (new->multiboot && config->cfi->mbHyperFirst) {
2728        /* fall through to LT_HYPER */
2729     } else {
2730        newLine = addLine(new, config->cfi, LT_KERNEL,
2731          config->primaryIndent,
2732          newKernelPath + strlen(prefix));
2733        needs &= ~NEED_KERNEL;
2734        break;
2735     }
2736    
2737        case LT_HYPER:
2738     newLine = addLine(new, config->cfi, LT_HYPER,
2739      config->primaryIndent,
2740      newMBKernel + strlen(prefix));
2741     needs &= ~NEED_MB;
2742   break;   break;
         }  
2743    
2744   switch (config->cfi->keywords[i].type) {      case LT_TITLE:
2745      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
2746       chptr = newKernelPath + strlen(prefix);   char * templabel;
2747       type = LT_KERNEL; break;   int x = 0, y = 0;
2748      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;  
2749       type = LT_TITLE; break;   templabel = strdup(newKernelTitle);
2750      default:       while( templabel[x]){
2751                  /* zipl strikes again */   if( templabel[x] == ' ' ){
2752                  if (config->cfi->titleBracketed) {   y = x;
2753                      needs &= ~KERNEL_TITLE;   while( templabel[y] ){
2754                      chptr = newKernelTitle;   templabel[y] = templabel[y+1];
2755                      type = LT_TITLE;   y++;
2756                      break;   }
2757                  } else {   }
2758                      abort();   x++;
2759                  }   }
2760   }   newLine = addLine(new, config->cfi, LT_TITLE,
2761      config->primaryIndent, templabel);
2762     free(templabel);
2763     }else{
2764     newLine = addLine(new, config->cfi, LT_TITLE,
2765      config->primaryIndent, newKernelTitle);
2766     }
2767     needs &= ~NEED_TITLE;
2768     break;
2769    
2770   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
2771   new->lines = newLine;   abort();
2772     }
2773      }      }
2774    
2775      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
2776          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
2777              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entrySeparator.
2778                                config->secondaryIndent,       */
2779                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
2780          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
2781              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
2782                                config->secondaryIndent,    newKernelTitle);
2783                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
2784          /* don't need to check for title as it's guaranteed to have been      }
2785           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
2786           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
2787          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
2788              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
2789                                config->secondaryIndent,   needs &= ~NEED_MB;
2790                                newKernelInitrd + strlen(prefix));      }
2791      } else {      if (needs & NEED_KERNEL) {
2792          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
2793              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
2794                                config->secondaryIndent,        config->cfi)) ?
2795                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
2796          if (needs & KERNEL_TITLE)    config->secondaryIndent,
2797              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
2798                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
2799                                newKernelTitle);      }
2800          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
2801              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
2802                                config->secondaryIndent,    config->secondaryIndent,
2803                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
2804     needs &= ~NEED_MB;
2805        }
2806        if (needs & NEED_INITRD) {
2807     char *initrdVal;
2808     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
2809     newLine = addLine(new, config->cfi,
2810      (new->multiboot && getKeywordByType(LT_MBMODULE,
2811          config->cfi)) ?
2812      LT_MBMODULE : LT_INITRD,
2813      config->secondaryIndent,
2814      initrdVal);
2815     free(initrdVal);
2816     needs &= ~NEED_INITRD;
2817        }
2818    
2819        if (needs) {
2820     printf(_("grubby: needs=%d, aborting\n"), needs);
2821     abort();
2822      }      }
2823    
2824      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 2827  int addNewKernel(struct grubConfig * con
2827      return 0;      return 0;
2828  }  }
2829    
2830    static void traceback(int signum)
2831    {
2832        void *array[40];
2833        size_t size;
2834    
2835        signal(SIGSEGV, SIG_DFL);
2836        memset(array, '\0', sizeof (array));
2837        size = backtrace(array, 40);
2838    
2839        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
2840                (unsigned long)size);
2841        backtrace_symbols_fd(array, size, STDERR_FILENO);
2842        exit(1);
2843    }
2844    
2845  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
2846      poptContext optCon;      poptContext optCon;
2847      char * grubConfig = NULL;      char * grubConfig = NULL;
# Line 2283  int main(int argc, const char ** argv) { Line 2851  int main(int argc, const char ** argv) {
2851      int badImageOkay = 0;      int badImageOkay = 0;
2852      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
2853      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
2854        int configureExtLinux = 0;
2855      int bootloaderProbe = 0;      int bootloaderProbe = 0;
2856        int extraInitrdCount = 0;
2857      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
2858      char * newKernelPath = NULL;      char * newKernelPath = NULL;
2859      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 2869  int main(int argc, const char ** argv) {
2869      char * defaultKernel = NULL;      char * defaultKernel = NULL;
2870      char * removeArgs = NULL;      char * removeArgs = NULL;
2871      char * kernelInfo = NULL;      char * kernelInfo = NULL;
2872        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
2873      const char * chptr = NULL;      const char * chptr = NULL;
2874      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
2875      struct grubConfig * config;      struct grubConfig * config;
# Line 2339  int main(int argc, const char ** argv) { Line 2910  int main(int argc, const char ** argv) {
2910      _("display the path of the default kernel") },      _("display the path of the default kernel") },
2911   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
2912      _("configure elilo bootloader") },      _("configure elilo bootloader") },
2913     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
2914        _("configure extlinux bootloader (from syslinux)") },
2915   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
2916      _("configure grub bootloader") },      _("configure grub bootloader") },
2917   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
# Line 2346  int main(int argc, const char ** argv) { Line 2919  int main(int argc, const char ** argv) {
2919      _("kernel-path") },      _("kernel-path") },
2920   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
2921      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
2922     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
2923        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
2924   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
2925      _("configure lilo bootloader") },      _("configure lilo bootloader") },
2926   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 2957  int main(int argc, const char ** argv) {
2957   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
2958      };      };
2959    
2960        useextlinuxmenu=0;
2961    
2962        signal(SIGSEGV, traceback);
2963    
2964      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
2965      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
2966    
# Line 2391  int main(int argc, const char ** argv) { Line 2970  int main(int argc, const char ** argv) {
2970      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
2971      exit(0);      exit(0);
2972      break;      break;
2973      case 'i':
2974        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
2975         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
2976        } else {
2977     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
2978     return 1;
2979        }
2980        break;
2981   }   }
2982      }      }
2983    
# Line 2407  int main(int argc, const char ** argv) { Line 2994  int main(int argc, const char ** argv) {
2994      }      }
2995    
2996      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub + configureELilo +
2997   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
2998     configureExtLinux ) > 1) {
2999   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3000   return 1;   return 1;
3001      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
# Line 2426  int main(int argc, const char ** argv) { Line 3014  int main(int argc, const char ** argv) {
3014          cfi = &siloConfigType;          cfi = &siloConfigType;
3015      } else if (configureZipl) {      } else if (configureZipl) {
3016          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3017        } else if (configureExtLinux) {
3018     cfi = &extlinuxConfigType;
3019     useextlinuxmenu=1;
3020      }      }
3021    
3022      if (!cfi) {      if (!cfi) {
# Line 2465  int main(int argc, const char ** argv) { Line 3056  int main(int argc, const char ** argv) {
3056      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3057   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3058   return 1;   return 1;
3059      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3060    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3061    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3062   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3063   return 1;   return 1;
3064      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3111  int main(int argc, const char ** argv) {
3111   bootPrefix = "";   bootPrefix = "";
3112      }      }
3113    
3114        if (!cfi->mbAllowExtraInitRds &&
3115     extraInitrdCount > 0) {
3116     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3117     return 1;
3118        }
3119    
3120      if (bootloaderProbe) {      if (bootloaderProbe) {
3121   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, erc = 0;
3122   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3123    
3124   if (!access(grubConfigType.defaultConfig, F_OK)) {   if (!access(grubConfigType.defaultConfig, F_OK)) {
# Line 2540  int main(int argc, const char ** argv) { Line 3137  int main(int argc, const char ** argv) {
3137   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3138   }   }
3139    
3140     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3141        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3142        if (!lconfig)
3143     erc = 1;
3144        else
3145     erc = checkForExtLinux(lconfig);
3146     }
3147    
3148   if (lrc == 1 || grc == 1) return 1;   if (lrc == 1 || grc == 1) return 1;
3149    
3150   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3151   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3152     if (erc == 2) printf("extlinux\n");
3153    
3154   return 0;   return 0;
3155      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3167  int main(int argc, const char ** argv) {
3167   if (!entry) return 0;   if (!entry) return 0;
3168   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3169    
3170   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3171   if (!line) return 0;   if (!line) return 0;
3172    
3173          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2585  int main(int argc, const char ** argv) { Line 3190  int main(int argc, const char ** argv) {
3190      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3191      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3192                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3193        if (updateKernelPath && newKernelInitrd) {
3194                if (updateInitrd(config, updateKernelPath, bootPrefix,
3195                                 newKernelInitrd)) return 1;
3196        }
3197      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3198                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3199                         extraInitrds, extraInitrdCount,
3200                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3201            
3202    

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