Magellan Linux

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

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

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

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