Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1717 by niro, Sat Feb 18 00:47:17 2012 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39  #include "mount_by_label.h"  #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43    #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49  #define _(A) (A)  #define _(A) (A)
50    
51    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
52  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
53    
54  /* comments get lumped in with indention */  /* comments get lumped in with indention */
# Line 38  struct lineElement { Line 57  struct lineElement {
57      char * indent;      char * indent;
58  };  };
59    
60  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
61         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
62         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
63        LT_KERNEL       = 1 << 2,
64        LT_INITRD       = 1 << 3,
65        LT_HYPER        = 1 << 4,
66        LT_DEFAULT      = 1 << 5,
67        LT_MBMODULE     = 1 << 6,
68        LT_ROOT         = 1 << 7,
69        LT_FALLBACK     = 1 << 8,
70        LT_KERNELARGS   = 1 << 9,
71        LT_BOOT         = 1 << 10,
72        LT_BOOTROOT     = 1 << 11,
73        LT_LBA          = 1 << 12,
74        LT_OTHER        = 1 << 13,
75        LT_GENERIC      = 1 << 14,
76        LT_ECHO    = 1 << 16,
77        LT_MENUENTRY    = 1 << 17,
78        LT_ENTRY_END    = 1 << 18,
79        LT_SET_VARIABLE = 1 << 19,
80        LT_UNKNOWN      = 1 << 20,
81    };
82    
83  struct singleLine {  struct singleLine {
84      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 99  struct singleEntry {
99    
100  #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 */
101    
102  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
103  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
104  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
105  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
106  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
107    #define NEED_MB      (1 << 4)
108    #define NEED_END     (1 << 5)
109    
110  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
111  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 74  struct keywordTypes { Line 114  struct keywordTypes {
114      char * key;      char * key;
115      enum lineType_e type;      enum lineType_e type;
116      char nextChar;      char nextChar;
117  } ;      char separatorChar;
118    };
119    
120    struct configFileInfo;
121    
122    typedef const char *(*findConfigFunc)(struct configFileInfo *);
123    typedef const int (*writeLineFunc)(struct configFileInfo *,
124     struct singleLine *line);
125    
126  struct configFileInfo {  struct configFileInfo {
127      char * defaultConfig;      char * defaultConfig;
128        findConfigFunc findConfig;
129        writeLineFunc writeLine;
130      struct keywordTypes * keywords;      struct keywordTypes * keywords;
131      int defaultIsIndex;      int defaultIsIndex;
132        int defaultIsVariable;
133      int defaultSupportSaved;      int defaultSupportSaved;
134      enum lineType_e entrySeparator;      enum lineType_e entryStart;
135        enum lineType_e entryEnd;
136      int needsBootPrefix;      int needsBootPrefix;
137      int argsInQuotes;      int argsInQuotes;
138      int maxTitleLength;      int maxTitleLength;
139      int titleBracketed;      int titleBracketed;
140        int titlePosition;
141        int mbHyperFirst;
142        int mbInitRdIsModule;
143        int mbConcatArgs;
144        int mbAllowExtraInitRds;
145  };  };
146    
147  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 150  struct keywordTypes grubKeywords[] = {
150      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
151      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
152      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
153      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
154      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
155        { "kernel",     LT_HYPER,       ' ' },
156      { NULL,    0, 0 },      { NULL,    0, 0 },
157  };  };
158    
159    const char *grubFindConfig(struct configFileInfo *cfi) {
160        static const char *configFiles[] = {
161     "/etc/grub.conf",
162     "/boot/grub/grub.conf",
163     "/boot/grub/menu.lst",
164     NULL
165        };
166        static int i = -1;
167    
168        if (i == -1) {
169     for (i = 0; configFiles[i] != NULL; i++) {
170        dbgPrintf("Checking \"%s\": ", configFiles[i]);
171        if (!access(configFiles[i], R_OK)) {
172     dbgPrintf("found\n");
173     return configFiles[i];
174        }
175        dbgPrintf("not found\n");
176     }
177        }
178        return configFiles[i];
179    }
180    
181  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
182      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
183      grubKeywords,    /* keywords */      .keywords = grubKeywords,
184      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
185      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
186      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
187      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
188      0,    /* argsInQuotes */      .mbHyperFirst = 1,
189      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
190      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
191    };
192    
193    struct keywordTypes grub2Keywords[] = {
194        { "menuentry",  LT_MENUENTRY,   ' ' },
195        { "}",          LT_ENTRY_END,   ' ' },
196        { "echo",       LT_ECHO,        ' ' },
197        { "set",        LT_SET_VARIABLE,' ', '=' },
198        { "root",       LT_BOOTROOT,    ' ' },
199        { "default",    LT_DEFAULT,     ' ' },
200        { "fallback",   LT_FALLBACK,    ' ' },
201        { "linux",      LT_KERNEL,      ' ' },
202        { "initrd",     LT_INITRD,      ' ', ' ' },
203        { "module",     LT_MBMODULE,    ' ' },
204        { "kernel",     LT_HYPER,       ' ' },
205        { NULL, 0, 0 },
206    };
207    
208    const char *grub2FindConfig(struct configFileInfo *cfi) {
209        static const char *configFiles[] = {
210     "/boot/grub/grub-efi.cfg",
211     "/boot/grub/grub.cfg",
212     NULL
213        };
214        static int i = -1;
215        static const char *grub_cfg = "/boot/grub/grub.cfg";
216    
217        if (i == -1) {
218     for (i = 0; configFiles[i] != NULL; i++) {
219        dbgPrintf("Checking \"%s\": ", configFiles[i]);
220        if (!access(configFiles[i], R_OK)) {
221     dbgPrintf("found\n");
222     return configFiles[i];
223        }
224     }
225        }
226    
227        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
228         * that isn't in grub1, and if it exists, return the config file path
229         * that they use. */
230        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
231     dbgPrintf("found\n");
232     return grub_cfg;
233        }
234    
235        dbgPrintf("not found\n");
236        return configFiles[i];
237    }
238    
239    struct configFileInfo grub2ConfigType = {
240        .findConfig = grub2FindConfig,
241        .keywords = grub2Keywords,
242        .defaultIsIndex = 1,
243        .defaultSupportSaved = 0,
244        .defaultIsVariable = 1,
245        .entryStart = LT_MENUENTRY,
246        .entryEnd = LT_ENTRY_END,
247        .titlePosition = 1,
248        .needsBootPrefix = 1,
249        .mbHyperFirst = 1,
250        .mbInitRdIsModule = 1,
251        .mbAllowExtraInitRds = 1,
252  };  };
253    
254  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 282  struct keywordTypes yabootKeywords[] = {
282      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
283      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
284      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
285      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
286      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
287      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
288      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 302  struct keywordTypes liloKeywords[] = {
302      { NULL,    0, 0 },      { NULL,    0, 0 },
303  };  };
304    
305    struct keywordTypes eliloKeywords[] = {
306        { "label",    LT_TITLE,    '=' },
307        { "root",    LT_ROOT,    '=' },
308        { "default",    LT_DEFAULT,    '=' },
309        { "image",    LT_KERNEL,    '=' },
310        { "initrd",    LT_INITRD,    '=' },
311        { "append",    LT_KERNELARGS,  '=' },
312        { "vmm",    LT_HYPER,       '=' },
313        { NULL,    0, 0 },
314    };
315    
316  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
317      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
318      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 334  struct keywordTypes ziplKeywords[] = {
334      { NULL,         0, 0 },      { NULL,         0, 0 },
335  };  };
336    
337    struct keywordTypes extlinuxKeywords[] = {
338        { "label",    LT_TITLE,    ' ' },
339        { "root",    LT_ROOT,    ' ' },
340        { "default",    LT_DEFAULT,    ' ' },
341        { "kernel",    LT_KERNEL,    ' ' },
342        { "initrd",    LT_INITRD,      ' ', ',' },
343        { "append",    LT_KERNELARGS,  ' ' },
344        { "prompt",     LT_UNKNOWN,     ' ' },
345        { NULL,    0, 0 },
346    };
347    int useextlinuxmenu;
348  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
349      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
350      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
351      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
352      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
353      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
354      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
355  };  };
356    
357  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
358      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
359      liloKeywords,    /* keywords */      .keywords = liloKeywords,
360      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
361      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
362      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
363  };  };
364    
365  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
366      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
367      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
368      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
369      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
370      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
371      1,    /* needsBootPrefix */      .maxTitleLength = 15,
372      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
373  };  };
374    
375  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
376      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
377      siloKeywords,    /* keywords */      .keywords = siloKeywords,
378      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
379      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
380      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
381      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
382  };  };
383    
384  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
385      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
386      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
387      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
388      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
389      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
390      0,    /* needsBootPrefix */  };
391      1,    /* argsInQuotes */  
392      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
393      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
394        .keywords = extlinuxKeywords,
395        .entryStart = LT_TITLE,
396        .needsBootPrefix = 1,
397        .maxTitleLength = 255,
398        .mbAllowExtraInitRds = 1,
399  };  };
400    
401  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 410  struct grubConfig {
410      struct configFileInfo * cfi;      struct configFileInfo * cfi;
411  };  };
412    
413    blkid_cache blkid;
414    
415  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
416  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
417       const char * path, const char * prefix,       const char * path, const char * prefix,
418       int * index);       int * index);
 static char * strndup(char * from, int len);  
419  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
420  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
421    struct singleLine * lineDup(struct singleLine * line);
422  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
423  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
424       struct configFileInfo * cfi);       struct configFileInfo * cfi);
425  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
426         struct configFileInfo * cfi);         struct configFileInfo * cfi);
427  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
428    static void requote(struct singleLine *line, struct configFileInfo * cfi);
429  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
430      char * to;    const char * item, int insertHere,
431      struct configFileInfo * cfi);
432      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
433      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
434      to[len] = '\0';        struct configFileInfo * cfi);
435    static enum lineType_e getTypeByKeyword(char * keyword,
436      return to;   struct configFileInfo * cfi);
437  }  static struct singleLine * getLineByType(enum lineType_e type,
438     struct singleLine * line);
439    static int checkForExtLinux(struct grubConfig * config);
440    struct singleLine * addLineTmpl(struct singleEntry * entry,
441                                    struct singleLine * tmplLine,
442                                    struct singleLine * prevLine,
443                                    const char * val,
444     struct configFileInfo * cfi);
445    struct singleLine *  addLine(struct singleEntry * entry,
446                                 struct configFileInfo * cfi,
447                                 enum lineType_e type, char * defaultIndent,
448                                 const char * val);
449    
450  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
451  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 480  static char * sdupprintf(const char *for
480      return buf;      return buf;
481  }  }
482    
483    static struct keywordTypes * getKeywordByType(enum lineType_e type,
484          struct configFileInfo * cfi) {
485        struct keywordTypes * kw;
486        for (kw = cfi->keywords; kw->key; kw++) {
487     if (kw->type == type)
488        return kw;
489        }
490        return NULL;
491    }
492    
493    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
494        struct keywordTypes *kt = getKeywordByType(type, cfi);
495        if (kt)
496     return kt->key;
497        return "unknown";
498    }
499    
500    static char * getpathbyspec(char *device) {
501        if (!blkid)
502            blkid_get_cache(&blkid, NULL);
503    
504        return blkid_get_devname(blkid, device, NULL);
505    }
506    
507    static char * getuuidbydev(char *device) {
508        if (!blkid)
509     blkid_get_cache(&blkid, NULL);
510    
511        return blkid_get_tag_value(blkid, "UUID", device);
512    }
513    
514    static enum lineType_e getTypeByKeyword(char * keyword,
515     struct configFileInfo * cfi) {
516        struct keywordTypes * kw;
517        for (kw = cfi->keywords; kw->key; kw++) {
518     if (!strcmp(keyword, kw->key))
519        return kw->type;
520        }
521        return LT_UNKNOWN;
522    }
523    
524    static struct singleLine * getLineByType(enum lineType_e type,
525     struct singleLine * line) {
526        dbgPrintf("getLineByType(%d): ", type);
527        for (; line; line = line->next) {
528     dbgPrintf("%d:%s ", line->type,
529      line->numElements ? line->elements[0].item : "(empty)");
530     if (line->type & type) break;
531        }
532        dbgPrintf(line ? "\n" : " (failed)\n");
533        return line;
534    }
535    
536  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
537      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
538          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
539          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
540              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 546  static int isBracketedTitle(struct singl
546      return 0;      return 0;
547  }  }
548    
549  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
550                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
551      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
552   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;  
553  }  }
554    
555  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 600  static void lineInit(struct singleLine *
600      line->next = NULL;      line->next = NULL;
601  }  }
602    
603    struct singleLine * lineDup(struct singleLine * line) {
604        int i;
605        struct singleLine * newLine = malloc(sizeof(*newLine));
606    
607        newLine->indent = strdup(line->indent);
608        newLine->next = NULL;
609        newLine->type = line->type;
610        newLine->numElements = line->numElements;
611        newLine->elements = malloc(sizeof(*newLine->elements) *
612           newLine->numElements);
613    
614        for (i = 0; i < newLine->numElements; i++) {
615     newLine->elements[i].indent = strdup(line->elements[i].indent);
616     newLine->elements[i].item = strdup(line->elements[i].item);
617        }
618    
619        return newLine;
620    }
621    
622  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
623      int i;      int i;
624    
# Line 414  static int lineWrite(FILE * out, struct Line 644  static int lineWrite(FILE * out, struct
644      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
645    
646   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
647   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
648        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
649      }      }
650    
651      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 664  static int getNextLine(char ** bufPtr, s
664      char * chptr;      char * chptr;
665      int elementsAlloced = 0;      int elementsAlloced = 0;
666      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
667      int first = 1;      int first = 1;
     int i;  
668    
669      lineFree(line);      lineFree(line);
670    
# Line 489  static int getNextLine(char ** bufPtr, s Line 718  static int getNextLine(char ** bufPtr, s
718      if (!line->numElements)      if (!line->numElements)
719   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
720      else {      else {
721   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
722      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;  
               
723              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
724               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
725              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 755  static int getNextLine(char ** bufPtr, s
755   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
756   line->numElements = 0;   line->numElements = 0;
757      }      }
758     } else {
759     struct keywordTypes *kw;
760    
761     kw = getKeywordByType(line->type, cfi);
762    
763     /* space isn't the only separator, we need to split
764     * elements up more
765     */
766     if (!isspace(kw->separatorChar)) {
767        int i;
768        char indent[2] = "";
769        indent[0] = kw->separatorChar;
770        for (i = 1; i < line->numElements; i++) {
771     char *p;
772     int j;
773     int numNewElements;
774    
775     numNewElements = 0;
776     p = line->elements[i].item;
777     while (*p != '\0') {
778     if (*p == kw->separatorChar)
779     numNewElements++;
780     p++;
781     }
782     if (line->numElements + numNewElements >= elementsAlloced) {
783     elementsAlloced += numNewElements + 5;
784     line->elements = realloc(line->elements,
785        sizeof(*line->elements) * elementsAlloced);
786     }
787    
788     for (j = line->numElements; j > i; j--) {
789     line->elements[j + numNewElements] = line->elements[j];
790     }
791     line->numElements += numNewElements;
792    
793     p = line->elements[i].item;
794     while (*p != '\0') {
795    
796     while (*p != kw->separatorChar && *p != '\0') p++;
797     if (*p == '\0') {
798     break;
799     }
800    
801     free(line->elements[i].indent);
802     line->elements[i].indent = strdup(indent);
803     *p++ = '\0';
804     i++;
805     line->elements[i].item = strdup(p);
806     line->elements[i].indent = strdup("");
807     p = line->elements[i].item;
808     }
809        }
810     }
811   }   }
812      }      }
813    
# Line 595  static struct grubConfig * readConfig(co Line 871  static struct grubConfig * readConfig(co
871      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
872   }   }
873    
874   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi)) {
875      sawEntry = 1;      sawEntry = 1;
876      if (!entry) {      if (!entry) {
877   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 887  static struct grubConfig * readConfig(co
887      entry->next = NULL;      entry->next = NULL;
888   }   }
889    
890   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
891        int i;
892        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
893        dbgPrintf("%s", line->indent);
894        for (i = 0; i < line->numElements; i++)
895     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
896        dbgPrintf("\n");
897        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
898        if (kwType && line->numElements == 3 &&
899        !strcmp(line->elements[1].item, kwType->key)) {
900     dbgPrintf("Line sets default config\n");
901     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
902     defaultLine = line;
903        }
904     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
905      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
906      defaultLine = line;      defaultLine = line;
907    
908            } else if (line->type == LT_KERNEL) {
909        /* if by some freak chance this is multiboot and the "module"
910         * lines came earlier in the template, make sure to use LT_HYPER
911         * instead of LT_KERNEL now
912         */
913        if (entry->multiboot)
914     line->type = LT_HYPER;
915    
916          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
917        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
918         * instead, now that we know this is a multiboot entry.
919         * This only applies to grub, but that's the only place we
920         * should find LT_MBMODULE lines anyway.
921         */
922        struct singleLine * l;
923        for (l = entry->lines; l; l = l->next) {
924     if (l->type == LT_HYPER)
925        break;
926     else if (l->type == LT_KERNEL) {
927        l->type = LT_HYPER;
928        break;
929     }
930        }
931              entry->multiboot = 1;              entry->multiboot = 1;
932    
933     } else if (line->type == LT_HYPER) {
934        entry->multiboot = 1;
935    
936   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
937      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
938      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
939    
940   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
941      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
942      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 961  static struct grubConfig * readConfig(co
961      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
962      line->elements[1].item = buf;      line->elements[1].item = buf;
963      line->numElements = 2;      line->numElements = 2;
964    
965   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
966      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
967         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 971  static struct grubConfig * readConfig(co
971   int last, len;   int last, len;
972    
973   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
974      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
975     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
976    
977   last = line->numElements - 1;   last = line->numElements - 1;
978   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
979   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
980      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
981      }      }
   
982   }   }
983    
984   /* 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 998  static struct grubConfig * readConfig(co
998   movedLine = 1;   movedLine = 1;
999   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1000   }   }
1001    
1002   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1003     which was moved, drop it. */     which was moved, drop it. */
1004   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 1014  static struct grubConfig * readConfig(co
1014   entry->lines = line;   entry->lines = line;
1015      else      else
1016   last->next = line;   last->next = line;
1017        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1018    
1019        /* we could have seen this outside of an entry... if so, we
1020         * ignore it like any other line we don't grok */
1021        if (line->type == LT_ENTRY_END && sawEntry)
1022     sawEntry = 0;
1023   } else {   } else {
1024      if (!cfg->theLines)      if (!cfg->theLines)
1025   cfg->theLines = line;   cfg->theLines = line;
1026      else {      else
1027   last->next = line;   last->next = line;
1028      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1029   }   }
1030    
1031   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1033  static struct grubConfig * readConfig(co
1033    
1034      free(incoming);      free(incoming);
1035    
1036        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1037      if (defaultLine) {      if (defaultLine) {
1038   if (cfi->defaultSupportSaved &&   if (cfi->defaultIsVariable) {
1039        char *value = defaultLine->elements[2].item;
1040        while (*value && (*value == '"' || *value == '\'' ||
1041        *value == ' ' || *value == '\t'))
1042     value++;
1043        cfg->defaultImage = strtol(value, &end, 10);
1044        while (*end && (*end == '"' || *end == '\'' ||
1045        *end == ' ' || *end == '\t'))
1046     end++;
1047        if (*end) cfg->defaultImage = -1;
1048     } else if (cfi->defaultSupportSaved &&
1049   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1050      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1051   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1066  static struct grubConfig * readConfig(co
1066                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1067                  }                  }
1068   i++;   i++;
1069     entry = NULL;
1070      }      }
1071    
1072      if (entry) cfg->defaultImage = i;      if (entry){
1073            cfg->defaultImage = i;
1074        }else{
1075            cfg->defaultImage = -1;
1076        }
1077   }   }
1078        } else {
1079            cfg->defaultImage = 0;
1080      }      }
1081    
1082      return cfg;      return cfg;
# Line 751  static void writeDefault(FILE * out, cha Line 1094  static void writeDefault(FILE * out, cha
1094   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1095      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1096   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1097      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1098      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1099     cfg->defaultImage);
1100        } else {
1101     fprintf(out, "%sdefault%s%d\n", indent, separator,
1102     cfg->defaultImage);
1103        }
1104   } else {   } else {
1105      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1106    
# Line 769  static void writeDefault(FILE * out, cha Line 1117  static void writeDefault(FILE * out, cha
1117    
1118      if (!entry) return;      if (!entry) return;
1119    
1120      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1121    
1122      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1123   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1151  static int writeConfig(struct grubConfig
1151      int rc;      int rc;
1152    
1153      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1154         directory to / */         directory to the dir of the symlink */
1155      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1156      do {      do {
1157   buf = alloca(len + 1);   buf = alloca(len + 1);
1158   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1159   if (rc == len) len += 256;   if (rc == len) len += 256;
1160      } while (rc == len);      } while (rc == len);
1161            
# Line 843  static int writeConfig(struct grubConfig Line 1190  static int writeConfig(struct grubConfig
1190      }      }
1191    
1192      line = cfg->theLines;      line = cfg->theLines;
1193        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1194      while (line) {      while (line) {
1195   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1196     line->numElements == 3 &&
1197     !strcmp(line->elements[1].item, defaultKw->key)) {
1198        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1199        needs &= ~MAIN_DEFAULT;
1200     } else if (line->type == LT_DEFAULT) {
1201      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1202      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1203   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1265  static int numEntries(struct grubConfig
1265      return i;      return i;
1266  }  }
1267    
1268    static char *findDiskForRoot()
1269    {
1270        int fd;
1271        char buf[65536];
1272        char *devname;
1273        char *chptr;
1274        int rc;
1275    
1276        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1277            fprintf(stderr, "grubby: failed to open %s: %s\n",
1278                    _PATH_MOUNTED, strerror(errno));
1279            return NULL;
1280        }
1281    
1282        rc = read(fd, buf, sizeof(buf) - 1);
1283        if (rc <= 0) {
1284            fprintf(stderr, "grubby: failed to read %s: %s\n",
1285                    _PATH_MOUNTED, strerror(errno));
1286            close(fd);
1287            return NULL;
1288        }
1289        close(fd);
1290        buf[rc] = '\0';
1291        chptr = buf;
1292    
1293        while (chptr && chptr != buf+rc) {
1294            devname = chptr;
1295    
1296            /*
1297             * The first column of a mtab entry is the device, but if the entry is a
1298             * special device it won't start with /, so move on to the next line.
1299             */
1300            if (*devname != '/') {
1301                chptr = strchr(chptr, '\n');
1302                if (chptr)
1303                    chptr++;
1304                continue;
1305            }
1306    
1307            /* Seek to the next space */
1308            chptr = strchr(chptr, ' ');
1309            if (!chptr) {
1310                fprintf(stderr, "grubby: error parsing %s: %s\n",
1311                        _PATH_MOUNTED, strerror(errno));
1312                return NULL;
1313            }
1314    
1315            /*
1316             * The second column of a mtab entry is the mount point, we are looking
1317             * for '/' obviously.
1318             */
1319            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1320                /*
1321                 * Move back 2, which is the first space after the device name, set
1322                 * it to \0 so strdup will just get the devicename.
1323                 */
1324                chptr -= 2;
1325                *chptr = '\0';
1326                return strdup(devname);
1327            }
1328    
1329            /* Next line */
1330            chptr = strchr(chptr, '\n');
1331            if (chptr)
1332                chptr++;
1333        }
1334    
1335        return NULL;
1336    }
1337    
1338  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1339    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1340      struct singleLine * line;      struct singleLine * line;
1341      char * fullName;      char * fullName;
1342      int i;      int i;
     struct stat sb, sb2;  
1343      char * dev;      char * dev;
     char * end;  
1344      char * rootspec;      char * rootspec;
1345        char * rootdev;
1346    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
       
     if (!line) return 0;  
1347      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) return 0;
1348      if (line->numElements < 2) return 0;  
1349        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1350        if (!line || line->numElements < 2) return 0;
1351    
1352      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1353    
# Line 935  int suitableImage(struct singleEntry * e Line 1355  int suitableImage(struct singleEntry * e
1355        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1356      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1357      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1358              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
                                       strlen(rootspec) : 0));  
1359      if (access(fullName, R_OK)) return 0;      if (access(fullName, R_OK)) return 0;
1360    
1361      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 945  int suitableImage(struct singleEntry * e Line 1364  int suitableImage(struct singleEntry * e
1364   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1365      } else {      } else {
1366   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1367   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1368    
1369   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1370      dev = line->elements[1].item;      dev = line->elements[1].item;
1371   } else {   } else {
1372              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1373      /* 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.
1374      line = entry->lines;       */
1375        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1376    
1377              /* failed to find one */              /* failed to find one */
1378              if (!line) return 0;              if (!line) return 0;
# Line 973  int suitableImage(struct singleEntry * e Line 1388  int suitableImage(struct singleEntry * e
1388   }   }
1389      }      }
1390    
1391      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1392   dev += 6;      if (!dev)
1393            return 0;
1394   /* check which device has this label */  
1395   dev = get_spec_by_volume_label(dev, &i, &i);      rootdev = findDiskForRoot();
1396   if (!dev) return 0;      if (!rootdev)
1397     return 0;
1398    
1399        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1400            free(rootdev);
1401            return 0;
1402      }      }
1403    
1404      if (*dev == '/') {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1405   if (stat(dev, &sb))   free(rootdev);
1406      return 0;          return 0;
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1407      }      }
     stat("/", &sb2);  
1408    
1409      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1410    
1411      return 1;      return 1;
1412  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1450  struct singleEntry * findEntryByPath(str
1450   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1451   if (!entry) return NULL;   if (!entry) return NULL;
1452    
1453   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1454   if (!line) return NULL;   if (!line) return NULL;
1455    
1456   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1492  struct singleEntry * findEntryByPath(str
1492      kernel += 6;      kernel += 6;
1493   }   }
1494    
1495   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1496      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1497    
1498        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1499    
1500      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1501                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1502          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1503                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1504                              kernel + strlen(prefix)))       checkType, line);
1505                      break;   if (!line) break;  /* not found in this entry */
1506              }  
1507                 if (line && line->numElements >= 2) {
1508              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1509              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1510                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1511                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1512                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1513                      if (!strcmp(line->elements[1].item  +   }
1514                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1515    
1516      i++;      /* make sure this entry has a kernel identifier; this skips
1517         * non-Linux boot entries (could find netbsd etc, though, which is
1518         * unfortunate)
1519         */
1520        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1521     break; /* found 'im! */
1522   }   }
1523    
1524   if (index) *index = i;   if (index) *index = i;
1525      }      }
1526    
     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);  
     }  
   
1527      return entry;      return entry;
1528  }  }
1529    
# Line 1286  void displayEntry(struct singleEntry * e Line 1688  void displayEntry(struct singleEntry * e
1688      char * root = NULL;      char * root = NULL;
1689      int i;      int i;
1690    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1691      printf("index=%d\n", index);      printf("index=%d\n", index);
1692    
1693        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1694        if (!line) {
1695            printf("non linux entry\n");
1696            return;
1697        }
1698    
1699      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1700    
1701      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1713  void displayEntry(struct singleEntry * e
1713   }   }
1714   printf("\"\n");   printf("\"\n");
1715      } else {      } else {
1716   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1717   if (line) {   if (line) {
1718      char * s;      char * s;
1719    
# Line 1334  void displayEntry(struct singleEntry * e Line 1737  void displayEntry(struct singleEntry * e
1737      }      }
1738    
1739      if (!root) {      if (!root) {
1740   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1741   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1742      root=line->elements[1].item;      root=line->elements[1].item;
1743      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1752  void displayEntry(struct singleEntry * e
1752   printf("root=%s\n", s);   printf("root=%s\n", s);
1753      }      }
1754    
1755      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1756    
1757      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1758   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1769  int parseSysconfigGrub(int * lbaPtr, cha
1769      char * start;      char * start;
1770      char * param;      char * param;
1771    
1772      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1773      if (!in) return 1;      if (!in) return 1;
1774    
1775      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1831  int displayInfo(struct grubConfig * conf
1831   return 1;   return 1;
1832      }      }
1833    
1834      /* 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
1835         be a better way */         be a better way */
1836      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1837   dumpSysconfigGrub();   dumpSysconfigGrub();
1838      } else {      } else {
1839   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1840   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1841      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1842   }   }
1843    
1844   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1845   if (line) printf("lba\n");   if (line) printf("lba\n");
1846      }      }
1847    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1856  int displayInfo(struct grubConfig * conf
1856      return 0;      return 0;
1857  }  }
1858    
1859    struct singleLine * addLineTmpl(struct singleEntry * entry,
1860     struct singleLine * tmplLine,
1861     struct singleLine * prevLine,
1862     const char * val,
1863     struct configFileInfo * cfi)
1864    {
1865        struct singleLine * newLine = lineDup(tmplLine);
1866    
1867        if (val) {
1868     /* override the inherited value with our own.
1869     * This is a little weak because it only applies to elements[1]
1870     */
1871     if (newLine->numElements > 1)
1872        removeElement(newLine, 1);
1873     insertElement(newLine, val, 1, cfi);
1874    
1875     /* but try to keep the rootspec from the template... sigh */
1876     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1877        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1878        if (rootspec != NULL) {
1879     free(newLine->elements[1].item);
1880     newLine->elements[1].item =
1881        sdupprintf("%s%s", rootspec, val);
1882        }
1883     }
1884        }
1885    
1886        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1887          newLine->elements[0].item : "");
1888    
1889        if (!entry->lines) {
1890     /* first one on the list */
1891     entry->lines = newLine;
1892        } else if (prevLine) {
1893     /* add after prevLine */
1894     newLine->next = prevLine->next;
1895     prevLine->next = newLine;
1896        }
1897    
1898        return newLine;
1899    }
1900    
1901  /* val may be NULL */  /* val may be NULL */
1902  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1903       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1904       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1905       char * val) {       const char * val) {
1906      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1907      int i;      struct keywordTypes * kw;
1908        struct singleLine tmpl;
1909    
1910      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1911   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1912      if (type != LT_TITLE || !cfi->titleBracketed)       */
1913          if (!cfi->keywords[i].key) abort();  
1914        if (type == LT_TITLE && cfi->titleBracketed) {
1915     /* we're doing a bracketed title (zipl) */
1916     tmpl.type = type;
1917     tmpl.numElements = 1;
1918     tmpl.elements = alloca(sizeof(*tmpl.elements));
1919     tmpl.elements[0].item = alloca(strlen(val)+3);
1920     sprintf(tmpl.elements[0].item, "[%s]", val);
1921     tmpl.elements[0].indent = "";
1922     val = NULL;
1923        } else if (type == LT_MENUENTRY) {
1924     char *lineend = "--class gnu-linux --class gnu --class os {";
1925     if (!val) {
1926        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
1927        abort();
1928     }
1929     kw = getKeywordByType(type, cfi);
1930     if (!kw) {
1931        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1932        abort();
1933     }
1934     tmpl.indent = "";
1935     tmpl.type = type;
1936     tmpl.numElements = 3;
1937     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1938     tmpl.elements[0].item = kw->key;
1939     tmpl.elements[0].indent = alloca(2);
1940     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1941     tmpl.elements[1].item = (char *)val;
1942     tmpl.elements[1].indent = alloca(2);
1943     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
1944     tmpl.elements[2].item = alloca(strlen(lineend)+1);
1945     strcpy(tmpl.elements[2].item, lineend);
1946     tmpl.elements[2].indent = "";
1947        } else {
1948     kw = getKeywordByType(type, cfi);
1949     if (!kw) {
1950        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1951        abort();
1952     }
1953     tmpl.type = type;
1954     tmpl.numElements = val ? 2 : 1;
1955     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1956     tmpl.elements[0].item = kw->key;
1957     tmpl.elements[0].indent = alloca(2);
1958     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1959     if (val) {
1960        tmpl.elements[1].item = (char *)val;
1961        tmpl.elements[1].indent = "";
1962     }
1963        }
1964    
1965      /* 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
1966         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1967         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
1968         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1969         differently from the rest) */         differently from the rest) */
1970      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1971   line = entry->lines;   if (line->numElements) prev = line;
1972   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1973   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;  
1974      }      }
1975    
1976      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
1977          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
1978          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
1979          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
1980          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
1981          line->elements[0].indent = malloc(2);   else
1982          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
1983          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
1984             if (menuEntry)
1985          if (val) {      tmpl.indent = "\t";
1986              line->elements[1].item = val;   else if (prev == entry->lines)
1987              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
1988          }   else
1989      } else {      tmpl.indent = prev->indent;
         /* 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("");  
1990      }      }
1991    
1992      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1993  }  }
1994    
1995  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2014  void removeLine(struct singleEntry * ent
2014      free(line);      free(line);
2015  }  }
2016    
2017    static int isquote(char q)
2018    {
2019        if (q == '\'' || q == '\"')
2020     return 1;
2021        return 0;
2022    }
2023    
2024    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2025    {
2026        struct singleLine newLine = {
2027     .indent = tmplLine->indent,
2028     .type = tmplLine->type,
2029     .next = tmplLine->next,
2030        };
2031        int firstQuotedItem = -1;
2032        int quoteLen = 0;
2033        int j;
2034        int element = 0;
2035        char *c;
2036    
2037        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2038        strcpy(c, tmplLine->elements[0].item);
2039        insertElement(&newLine, c, element++, cfi);
2040        free(c);
2041        c = NULL;
2042    
2043        for (j = 1; j < tmplLine->numElements; j++) {
2044     if (firstQuotedItem == -1) {
2045        quoteLen += strlen(tmplLine->elements[j].item);
2046        
2047        if (isquote(tmplLine->elements[j].item[0])) {
2048     firstQuotedItem = j;
2049            quoteLen += strlen(tmplLine->elements[j].indent);
2050        } else {
2051     c = malloc(quoteLen + 1);
2052     strcpy(c, tmplLine->elements[j].item);
2053     insertElement(&newLine, c, element++, cfi);
2054     free(c);
2055     quoteLen = 0;
2056        }
2057     } else {
2058        int itemlen = strlen(tmplLine->elements[j].item);
2059        quoteLen += itemlen;
2060        quoteLen += strlen(tmplLine->elements[j].indent);
2061        
2062        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2063     c = malloc(quoteLen + 1);
2064     c[0] = '\0';
2065     for (int i = firstQuotedItem; i < j+1; i++) {
2066        strcat(c, tmplLine->elements[i].item);
2067        strcat(c, tmplLine->elements[i].indent);
2068     }
2069     insertElement(&newLine, c, element++, cfi);
2070     free(c);
2071    
2072     firstQuotedItem = -1;
2073     quoteLen = 0;
2074        }
2075     }
2076        }
2077        while (tmplLine->numElements)
2078     removeElement(tmplLine, 0);
2079        if (tmplLine->elements)
2080     free(tmplLine->elements);
2081    
2082        tmplLine->numElements = newLine.numElements;
2083        tmplLine->elements = newLine.elements;
2084    }
2085    
2086    static void insertElement(struct singleLine * line,
2087      const char * item, int insertHere,
2088      struct configFileInfo * cfi)
2089    {
2090        struct keywordTypes * kw;
2091        char indent[2] = "";
2092    
2093        /* sanity check */
2094        if (insertHere > line->numElements) {
2095     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2096      insertHere, line->numElements);
2097     insertHere = line->numElements;
2098        }
2099    
2100        line->elements = realloc(line->elements, (line->numElements + 1) *
2101         sizeof(*line->elements));
2102        memmove(&line->elements[insertHere+1],
2103        &line->elements[insertHere],
2104        (line->numElements - insertHere) *
2105        sizeof(*line->elements));
2106        line->elements[insertHere].item = strdup(item);
2107    
2108        kw = getKeywordByType(line->type, cfi);
2109    
2110        if (line->numElements == 0) {
2111     indent[0] = '\0';
2112        } else if (insertHere == 0) {
2113     indent[0] = kw->nextChar;
2114        } else if (kw->separatorChar != '\0') {
2115     indent[0] = kw->separatorChar;
2116        } else {
2117     indent[0] = ' ';
2118        }
2119    
2120        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2121     /* move the end-of-line forward */
2122     line->elements[insertHere].indent =
2123        line->elements[insertHere-1].indent;
2124     line->elements[insertHere-1].indent = strdup(indent);
2125        } else {
2126     line->elements[insertHere].indent = strdup(indent);
2127        }
2128    
2129        line->numElements++;
2130    
2131        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2132          line->elements[0].item,
2133          line->elements[insertHere].item,
2134          line->elements[insertHere].indent,
2135          insertHere);
2136    }
2137    
2138    static void removeElement(struct singleLine * line, int removeHere) {
2139        int i;
2140    
2141        /* sanity check */
2142        if (removeHere >= line->numElements) return;
2143    
2144        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2145          removeHere, line->elements[removeHere].item);
2146    
2147        free(line->elements[removeHere].item);
2148    
2149        if (removeHere > 1) {
2150     /* previous argument gets this argument's post-indentation */
2151     free(line->elements[removeHere-1].indent);
2152     line->elements[removeHere-1].indent =
2153        line->elements[removeHere].indent;
2154        } else {
2155     free(line->elements[removeHere].indent);
2156        }
2157    
2158        /* now collapse the array, but don't bother to realloc smaller */
2159        for (i = removeHere; i < line->numElements - 1; i++)
2160     line->elements[i] = line->elements[i + 1];
2161    
2162        line->numElements--;
2163    }
2164    
2165  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2166      char * first, * second;      char * first, * second;
2167      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2184  int updateActualImage(struct grubConfig
2184      struct singleEntry * entry;      struct singleEntry * entry;
2185      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2186      int index = 0;      int index = 0;
2187      int i, j, k;      int i, k;
2188      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2189      const char ** arg;      const char ** arg;
2190      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2191      int firstElement;      int firstElement;
2192      int *usedElements, *usedArgs;      int *usedElements;
2193        int doreplace;
2194    
2195      if (!image) return 0;      if (!image) return 0;
2196    
# Line 1609  int updateActualImage(struct grubConfig Line 2217  int updateActualImage(struct grubConfig
2217   }   }
2218      }      }
2219    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2220    
2221      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2222   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2223    
2224      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2225   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2226    
2227      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2228    
2229      k = 0;   if (multibootArgs && !entry->multiboot)
2230      for (arg = newArgs; *arg; arg++)      continue;
2231          k++;  
2232      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2233     * LT_KERNELARGS, use that.  Otherwise use
2234     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2235     */
2236     if (useKernelArgs) {
2237        line = getLineByType(LT_KERNELARGS, entry->lines);
2238        if (!line) {
2239     /* no LT_KERNELARGS, need to add it */
2240     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2241           cfg->secondaryIndent, NULL);
2242        }
2243        firstElement = 1;
2244    
2245      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2246   index++;      line = getLineByType(LT_HYPER, entry->lines);
2247        if (!line) {
2248     /* a multiboot entry without LT_HYPER? */
2249     continue;
2250        }
2251        firstElement = 2;
2252    
2253   line = entry->lines;   } else {
2254   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2255   if (!line) continue;      if (!line) {
2256   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2257     continue;
2258          if (entry->multiboot && !multibootArgs) {      }
2259              /* 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;  
2260   }   }
2261    
2262   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2263      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2264      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2265     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2266        /* this is a multiboot entry, make sure there's
2267         * -- on the args line
2268         */
2269        for (i = firstElement; i < line->numElements; i++) {
2270     if (!strcmp(line->elements[i].item, "--"))
2271        break;
2272        }
2273        if (i == line->numElements) {
2274     /* assume all existing args are kernel args,
2275     * prepend -- to make it official
2276     */
2277     insertElement(line, "--", firstElement, cfg->cfi);
2278     i = firstElement;
2279        }
2280        if (!multibootArgs) {
2281     /* kernel args start after the -- */
2282     firstElement = i + 1;
2283        }
2284     } else if (cfg->cfi->mbConcatArgs) {
2285        /* this is a non-multiboot entry, remove hyper args */
2286        for (i = firstElement; i < line->numElements; i++) {
2287     if (!strcmp(line->elements[i].item, "--"))
2288        break;
2289        }
2290        if (i < line->numElements) {
2291     /* remove args up to -- */
2292     while (strcmp(line->elements[firstElement].item, "--"))
2293        removeElement(line, firstElement);
2294     /* remove -- */
2295     removeElement(line, firstElement);
2296        }
2297   }   }
2298    
2299          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2300    
2301          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2302   for (arg = newArgs; *arg; arg++) {  
2303              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2304      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2305     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2306        !strcmp(line->elements[i].item, "--"))
2307     {
2308        /* reached the end of hyper args, insert here */
2309        doreplace = 0;
2310        break;  
2311     }
2312                  if (usedElements[i])                  if (usedElements[i])
2313                      continue;                      continue;
2314   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2315                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2316      break;      break;
2317                  }                  }
2318              }              }
     chptr = strchr(*arg, '=');  
2319    
2320      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2321   /* replace */   /* direct replacement */
2322   free(line->elements[i].item);   free(line->elements[i].item);
2323   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("");  
  }  
2324    
2325   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2326   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2327      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2328   /* append */   if (rootLine) {
2329   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2330   (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(" ");  
2331   } else {   } else {
2332      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2333         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2334   }   }
2335        }
2336    
2337   line->numElements++;      else {
2338     /* insert/append */
2339     insertElement(line, *arg, i, cfg->cfi);
2340     usedElements = realloc(usedElements, line->numElements *
2341           sizeof(*usedElements));
2342     memmove(&usedElements[i + 1], &usedElements[i],
2343     line->numElements - i - 1);
2344     usedElements[i] = 1;
2345    
2346   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2347     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2348     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2349   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2350      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2351      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2352   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2353   }   }
2354      }      }
             k++;  
2355   }   }
2356    
2357          free(usedElements);          free(usedElements);
2358    
  /* 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? */  
2359   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2360      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2361   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2362        !strcmp(line->elements[i].item, "--"))
2363        /* reached the end of hyper args, stop here */
2364        break;
2365     if (!argMatch(line->elements[i].item, *arg)) {
2366        removeElement(line, i);
2367      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;  
2368   }   }
2369        }
2370   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2371        if (useRoot && !strncmp(*arg, "root=", 5)) {
2372   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2373      line->elements[j - 1] = line->elements[j];   if (rootLine)
2374        removeLine(entry, rootLine);
  line->numElements--;  
2375      }      }
2376   }   }
2377    
# Line 1760  int updateActualImage(struct grubConfig Line 2382  int updateActualImage(struct grubConfig
2382   }   }
2383      }      }
2384    
     free(usedArgs);  
2385      free(newArgs);      free(newArgs);
2386      free(oldArgs);      free(oldArgs);
2387    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2407  int updateImage(struct grubConfig * cfg,
2407      return rc;      return rc;
2408  }  }
2409    
2410    int updateInitrd(struct grubConfig * cfg, const char * image,
2411                     const char * prefix, const char * initrd) {
2412        struct singleEntry * entry;
2413        struct singleLine * line, * kernelLine, *endLine = NULL;
2414        int index = 0;
2415    
2416        if (!image) return 0;
2417    
2418        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2419            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2420            if (!kernelLine) continue;
2421    
2422            line = getLineByType(LT_INITRD, entry->lines);
2423            if (line)
2424                removeLine(entry, line);
2425            if (prefix) {
2426                int prefixLen = strlen(prefix);
2427                if (!strncmp(initrd, prefix, prefixLen))
2428                    initrd += prefixLen;
2429            }
2430     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2431     if (endLine)
2432        removeLine(entry, endLine);
2433            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2434            if (!line)
2435        return 1;
2436     if (endLine) {
2437        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2438                if (!line)
2439     return 1;
2440     }
2441    
2442            break;
2443        }
2444    
2445        return 0;
2446    }
2447    
2448  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2449      int fd;      int fd;
2450      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1956  int checkForLilo(struct grubConfig * con Line 2615  int checkForLilo(struct grubConfig * con
2615      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2616  }  }
2617    
2618    int checkForGrub2(struct grubConfig * config) {
2619        if (!access("/etc/grub.d/", R_OK))
2620     return 2;
2621    
2622        return 1;
2623    }
2624    
2625  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2626      int fd;      int fd;
2627      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2642  int checkForGrub(struct grubConfig * con
2642      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2643   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2644   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2645     close(fd);
2646     return 1;
2647        }
2648        close(fd);
2649    
2650        return checkDeviceBootloader(boot, bootSect);
2651    }
2652    
2653    int checkForExtLinux(struct grubConfig * config) {
2654        int fd;
2655        unsigned char bootSect[512];
2656        char * boot;
2657        char executable[] = "/boot/extlinux/extlinux";
2658    
2659        printf("entered: checkForExtLinux()\n");
2660    
2661        if (parseSysconfigGrub(NULL, &boot))
2662     return 0;
2663    
2664        /* assume grub is not installed -- not an error condition */
2665        if (!boot)
2666     return 0;
2667    
2668        fd = open(executable, O_RDONLY);
2669        if (fd < 0)
2670     /* this doesn't exist if grub hasn't been installed */
2671     return 0;
2672    
2673        if (read(fd, bootSect, 512) != 512) {
2674     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2675     executable, strerror(errno));
2676   return 1;   return 1;
2677      }      }
2678      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2691  static char * getRootSpecifier(char * st
2691      return rootspec;      return rootspec;
2692  }  }
2693    
2694    static char * getInitrdVal(struct grubConfig * config,
2695       const char * prefix, struct singleLine *tmplLine,
2696       const char * newKernelInitrd,
2697       char ** extraInitrds, int extraInitrdCount)
2698    {
2699        char *initrdVal, *end;
2700        int i;
2701        size_t totalSize;
2702        size_t prefixLen;
2703        char separatorChar;
2704    
2705        prefixLen = strlen(prefix);
2706        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2707    
2708        for (i = 0; i < extraInitrdCount; i++) {
2709     totalSize += sizeof(separatorChar);
2710     totalSize += strlen(extraInitrds[i]) - prefixLen;
2711        }
2712    
2713        initrdVal = end = malloc(totalSize);
2714    
2715        end = stpcpy (end, newKernelInitrd + prefixLen);
2716    
2717        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2718        for (i = 0; i < extraInitrdCount; i++) {
2719     const char *extraInitrd;
2720     int j;
2721    
2722     extraInitrd = extraInitrds[i] + prefixLen;
2723     /* Don't add entries that are already there */
2724     if (tmplLine != NULL) {
2725        for (j = 2; j < tmplLine->numElements; j++)
2726     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2727        break;
2728    
2729        if (j != tmplLine->numElements)
2730     continue;
2731     }
2732    
2733     *end++ = separatorChar;
2734     end = stpcpy(end, extraInitrd);
2735        }
2736    
2737        return initrdVal;
2738    }
2739    
2740  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2741           const char * prefix,           const char * prefix,
2742   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2743   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2744     char ** extraInitrds, int extraInitrdCount,
2745                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2746      struct singleEntry * new;      struct singleEntry * new;
2747      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2748      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2749      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2750    
2751      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2752    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2776  int addNewKernel(struct grubConfig * con
2776      config->entries = new;      config->entries = new;
2777    
2778      /* copy/update from the template */      /* copy/update from the template */
2779      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2780        if (newKernelInitrd)
2781     needs |= NEED_INITRD;
2782      if (newMBKernel) {      if (newMBKernel) {
2783          needs |= KERNEL_MB;          needs |= NEED_MB;
2784          new->multiboot = 1;          new->multiboot = 1;
2785      }      }
2786    
2787      if (template) {      if (template) {
2788   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2789      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2790      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2791   indent = tmplLine->indent;   {
2792        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2793    
2794      /* skip comments */      /* skip comments */
2795      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2796      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2797      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2798    
2799      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2800      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2801     if (!template->multiboot && (needs & NEED_MB)) {
2802              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2803                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2804                  struct singleLine *l;       * hypervisor at the same time.
2805                  needs &= ~ KERNEL_MB;       */
2806        if (config->cfi->mbHyperFirst) {
2807                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2808                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2809                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2810                      newMBKernel + strlen(prefix));
2811                  tmplLine = lastLine;   /* set up for adding the kernel line */
2812                  if (!new->lines) {   free(tmplLine->indent);
2813                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2814                  } else {   needs &= ~NEED_MB;
2815                      newLine->next = l;      }
2816                      newLine = l;      if (needs & NEED_KERNEL) {
2817                  }   /* use addLineTmpl to preserve line elements,
2818                  continue;   * otherwise we could just call addLine.  Unfortunately
2819              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2820                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2821                  continue; /* don't need multiboot kernel here */   * change below.
2822              }   */
2823     struct keywordTypes * mbm_kw =
2824        getKeywordByType(LT_MBMODULE, config->cfi);
2825     if (mbm_kw) {
2826        tmplLine->type = LT_MBMODULE;
2827        free(tmplLine->elements[0].item);
2828        tmplLine->elements[0].item = strdup(mbm_kw->key);
2829     }
2830     newLine = addLineTmpl(new, tmplLine, newLine,
2831          newKernelPath + strlen(prefix), config->cfi);
2832     needs &= ~NEED_KERNEL;
2833        }
2834        if (needs & NEED_MB) { /* !mbHyperFirst */
2835     newLine = addLine(new, config->cfi, LT_HYPER,
2836      config->secondaryIndent,
2837      newMBKernel + strlen(prefix));
2838     needs &= ~NEED_MB;
2839        }
2840     } else if (needs & NEED_KERNEL) {
2841        newLine = addLineTmpl(new, tmplLine, newLine,
2842      newKernelPath + strlen(prefix), config->cfi);
2843        needs &= ~NEED_KERNEL;
2844     }
2845    
2846      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2847   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2848   new->lines = newLine;   if (needs & NEED_MB) {
2849      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2850   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2851   newLine = newLine->next;      needs &= ~NEED_MB;
2852      }   }
2853    
2854        } else if (tmplLine->type == LT_MBMODULE &&
2855           tmplLine->numElements >= 2) {
2856     if (new->multiboot) {
2857        if (needs & NEED_KERNEL) {
2858     newLine = addLineTmpl(new, tmplLine, newLine,
2859          newKernelPath +
2860          strlen(prefix), config->cfi);
2861     needs &= ~NEED_KERNEL;
2862        } else if (config->cfi->mbInitRdIsModule &&
2863           (needs & NEED_INITRD)) {
2864     char *initrdVal;
2865     initrdVal = getInitrdVal(config, prefix, tmplLine,
2866     newKernelInitrd, extraInitrds,
2867     extraInitrdCount);
2868     newLine = addLineTmpl(new, tmplLine, newLine,
2869          initrdVal, config->cfi);
2870     free(initrdVal);
2871     needs &= ~NEED_INITRD;
2872        }
2873     } else if (needs & NEED_KERNEL) {
2874        /* template is multi but new is not,
2875         * insert the kernel in the first module slot
2876         */
2877        tmplLine->type = LT_KERNEL;
2878        free(tmplLine->elements[0].item);
2879        tmplLine->elements[0].item =
2880     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2881        newLine = addLineTmpl(new, tmplLine, newLine,
2882      newKernelPath + strlen(prefix), config->cfi);
2883        needs &= ~NEED_KERNEL;
2884     } else if (needs & NEED_INITRD) {
2885        char *initrdVal;
2886        /* template is multi but new is not,
2887         * insert the initrd in the second module slot
2888         */
2889        tmplLine->type = LT_INITRD;
2890        free(tmplLine->elements[0].item);
2891        tmplLine->elements[0].item =
2892     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2893        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2894        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2895        free(initrdVal);
2896        needs &= ~NEED_INITRD;
2897     }
2898    
     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));  
                 }  
2899      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2900      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2901   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2902   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2903                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2904                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2905                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2906                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2907                  }       */
2908                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2909                  if (rootspec != NULL) {   char *initrdVal;
2910                      newLine->elements[1].item = sdupprintf("%s%s",  
2911                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2912                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2913                                                             strlen(prefix));    config->secondaryIndent,
2914                  } else {    initrdVal);
2915                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2916                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2917                  }      }
2918              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2919                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2920   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2921                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2922                      free(newLine->elements[0].item);      free(initrdVal);
2923                      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);  
2924   }   }
2925    
2926   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
2927   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
2928   newLine->numElements = 2;   requote(tmplLine, config->cfi);
2929     char *nkt = malloc(strlen(newKernelTitle)+3);
2930     strcpy(nkt, "'");
2931     strcat(nkt, newKernelTitle);
2932     strcat(nkt, "'");
2933     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
2934     free(nkt);
2935     needs &= ~NEED_TITLE;
2936      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2937                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2938                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2939                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2940                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2941                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2942                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2943                                             newLine->numElements);     config->cfi->titleBracketed) {
2944        /* addLineTmpl doesn't handle titleBracketed */
2945                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2946                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2947                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2948                  newLine->numElements = 1;   }
2949              }      } else if (tmplLine->type == LT_ECHO) {
2950        requote(tmplLine, config->cfi);
2951        if (tmplLine->numElements > 1 &&
2952        strstr(tmplLine->elements[1].item, "'Loading Linux ")) {
2953     char *prefix = "'Loading ";
2954     char *newTitle = malloc(strlen(prefix) +
2955     strlen(newKernelTitle) + 2);
2956    
2957     strcpy(newTitle, prefix);
2958     strcat(newTitle, newKernelTitle);
2959     strcat(newTitle, "'");
2960     newLine = addLine(new, config->cfi, LT_ECHO,
2961     tmplLine->indent, newTitle);
2962     free(newTitle);
2963        } else {
2964     /* pass through other lines from the template */
2965     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
2966     config->cfi);
2967        }
2968        } else {
2969     /* pass through other lines from the template */
2970     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2971        }
2972   }   }
2973    
2974      } else {      } else {
2975   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2976      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2977     */
2978     switch (config->cfi->entryStart) {
2979        case LT_KERNEL:
2980     if (new->multiboot && config->cfi->mbHyperFirst) {
2981        /* fall through to LT_HYPER */
2982     } else {
2983        newLine = addLine(new, config->cfi, LT_KERNEL,
2984          config->primaryIndent,
2985          newKernelPath + strlen(prefix));
2986        needs &= ~NEED_KERNEL;
2987        break;
2988     }
2989    
2990        case LT_HYPER:
2991     newLine = addLine(new, config->cfi, LT_HYPER,
2992      config->primaryIndent,
2993      newMBKernel + strlen(prefix));
2994     needs &= ~NEED_MB;
2995   break;   break;
         }  
2996    
2997   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
2998      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
2999       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3000       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3001      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3002       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3003      default:        config->primaryIndent, nkt);
3004                  /* zipl strikes again */   free(nkt);
3005                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3006                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3007                      chptr = newKernelTitle;   break;
3008                      type = LT_TITLE;      }
3009                      break;      case LT_TITLE:
3010                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3011                      abort();   char * templabel;
3012                  }   int x = 0, y = 0;
3013   }  
3014     templabel = strdup(newKernelTitle);
3015     while( templabel[x]){
3016     if( templabel[x] == ' ' ){
3017     y = x;
3018     while( templabel[y] ){
3019     templabel[y] = templabel[y+1];
3020     y++;
3021     }
3022     }
3023     x++;
3024     }
3025     newLine = addLine(new, config->cfi, LT_TITLE,
3026      config->primaryIndent, templabel);
3027     free(templabel);
3028     }else{
3029     newLine = addLine(new, config->cfi, LT_TITLE,
3030      config->primaryIndent, newKernelTitle);
3031     }
3032     needs &= ~NEED_TITLE;
3033     break;
3034    
3035   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3036   new->lines = newLine;   abort();
3037     }
3038      }      }
3039    
3040      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3041          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3042              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3043                                config->secondaryIndent,       */
3044                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3045          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3046              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3047                                config->secondaryIndent,    newKernelTitle);
3048                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3049          /* don't need to check for title as it's guaranteed to have been      }
3050           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3051           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3052          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3053              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3054                                config->secondaryIndent,   needs &= ~NEED_MB;
3055                                newKernelInitrd + strlen(prefix));      }
3056      } else {      if (needs & NEED_KERNEL) {
3057          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3058              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3059                                config->secondaryIndent,        config->cfi)) ?
3060                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3061          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3062              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3063                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3064                                newKernelTitle);      }
3065          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3066              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3067                                config->secondaryIndent,    config->secondaryIndent,
3068                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3069     needs &= ~NEED_MB;
3070        }
3071        if (needs & NEED_INITRD) {
3072     char *initrdVal;
3073     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3074     newLine = addLine(new, config->cfi,
3075      (new->multiboot && getKeywordByType(LT_MBMODULE,
3076          config->cfi)) ?
3077      LT_MBMODULE : LT_INITRD,
3078      config->secondaryIndent,
3079      initrdVal);
3080     free(initrdVal);
3081     needs &= ~NEED_INITRD;
3082        }
3083        if (needs & NEED_END) {
3084     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3085     config->secondaryIndent, NULL);
3086     needs &= ~NEED_END;
3087        }
3088    
3089        if (needs) {
3090     printf(_("grubby: needs=%d, aborting\n"), needs);
3091     abort();
3092      }      }
3093    
3094      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3097  int addNewKernel(struct grubConfig * con
3097      return 0;      return 0;
3098  }  }
3099    
3100    static void traceback(int signum)
3101    {
3102        void *array[40];
3103        size_t size;
3104    
3105        signal(SIGSEGV, SIG_DFL);
3106        memset(array, '\0', sizeof (array));
3107        size = backtrace(array, 40);
3108    
3109        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3110                (unsigned long)size);
3111        backtrace_symbols_fd(array, size, STDERR_FILENO);
3112        exit(1);
3113    }
3114    
3115  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3116      poptContext optCon;      poptContext optCon;
3117      char * grubConfig = NULL;      const char * grubConfig = NULL;
3118      char * outputFile = NULL;      char * outputFile = NULL;
3119      int arg = 0;      int arg = 0;
3120      int flags = 0;      int flags = 0;
3121      int badImageOkay = 0;      int badImageOkay = 0;
3122        int configureGrub2 = 0;
3123      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3124      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3125        int configureExtLinux = 0;
3126      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3127        int extraInitrdCount = 0;
3128      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3129      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3130      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3140  int main(int argc, const char ** argv) {
3140      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3141      char * removeArgs = NULL;      char * removeArgs = NULL;
3142      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3143        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3144      const char * chptr = NULL;      const char * chptr = NULL;
3145      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3146      struct grubConfig * config;      struct grubConfig * config;
# Line 2339  int main(int argc, const char ** argv) { Line 3181  int main(int argc, const char ** argv) {
3181      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3182   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3183      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3184     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3185        _("configure extlinux bootloader (from syslinux)") },
3186   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3187      _("configure grub bootloader") },      _("configure grub bootloader") },
3188     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3189        _("configure grub2 bootloader") },
3190   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3191      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3192      _("kernel-path") },      _("kernel-path") },
3193   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3194      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3195     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3196        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3197   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3198      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3199   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3230  int main(int argc, const char ** argv) {
3230   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3231      };      };
3232    
3233        useextlinuxmenu=0;
3234    
3235        signal(SIGSEGV, traceback);
3236    
3237      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3238      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3239    
# Line 2391  int main(int argc, const char ** argv) { Line 3243  int main(int argc, const char ** argv) {
3243      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3244      exit(0);      exit(0);
3245      break;      break;
3246      case 'i':
3247        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3248         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3249        } else {
3250     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3251     return 1;
3252        }
3253        break;
3254   }   }
3255      }      }
3256    
# Line 2406  int main(int argc, const char ** argv) { Line 3266  int main(int argc, const char ** argv) {
3266   return 1;   return 1;
3267      }      }
3268    
3269      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3270   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3271     configureExtLinux ) > 1) {
3272   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3273   return 1;   return 1;
3274      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3275   fprintf(stderr,   fprintf(stderr,
3276      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3277   return 1;   return 1;
3278        } else if (configureGrub2) {
3279     cfi = &grub2ConfigType;
3280      } else if (configureLilo) {      } else if (configureLilo) {
3281   cfi = &liloConfigType;   cfi = &liloConfigType;
3282      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3289  int main(int argc, const char ** argv) {
3289          cfi = &siloConfigType;          cfi = &siloConfigType;
3290      } else if (configureZipl) {      } else if (configureZipl) {
3291          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3292        } else if (configureExtLinux) {
3293     cfi = &extlinuxConfigType;
3294     useextlinuxmenu=1;
3295      }      }
3296    
3297      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3306  int main(int argc, const char ** argv) {
3306        #elif __s390x__        #elif __s390x__
3307          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3308        #else        #else
3309   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3310        cfi = &grub2ConfigType;
3311     else
3312        cfi = &grubConfigType;
3313        #endif        #endif
3314      }      }
3315    
3316      if (!grubConfig)      if (!grubConfig) {
3317   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3318        grubConfig = cfi->findConfig(cfi);
3319     if (!grubConfig)
3320        grubConfig = cfi->defaultConfig;
3321        }
3322    
3323      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3324    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
# Line 2465  int main(int argc, const char ** argv) { Line 3338  int main(int argc, const char ** argv) {
3338      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3339   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3340   return 1;   return 1;
3341      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3342    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3343    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3344   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3345   return 1;   return 1;
3346      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3365  int main(int argc, const char ** argv) {
3365   defaultKernel = NULL;   defaultKernel = NULL;
3366      }      }
3367    
3368      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3369   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3370   "is used\n"));   "is used\n"));
3371   return 1;   return 1;
# Line 2520  int main(int argc, const char ** argv) { Line 3393  int main(int argc, const char ** argv) {
3393   bootPrefix = "";   bootPrefix = "";
3394      }      }
3395    
3396        if (!cfi->mbAllowExtraInitRds &&
3397     extraInitrdCount > 0) {
3398     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3399     return 1;
3400        }
3401    
3402      if (bootloaderProbe) {      if (bootloaderProbe) {
3403   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3404   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3405    
3406   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3407      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3408        gconfig = readConfig(grub2config, &grub2ConfigType);
3409        if (!gconfig)
3410     gr2c = 1;
3411        else
3412     gr2c = checkForGrub2(gconfig);
3413     }
3414    
3415     const char *grubconfig = grubFindConfig(&grubConfigType);
3416     if (!access(grubconfig, F_OK)) {
3417        gconfig = readConfig(grubconfig, &grubConfigType);
3418      if (!gconfig)      if (!gconfig)
3419   grc = 1;   grc = 1;
3420      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3429  int main(int argc, const char ** argv) {
3429   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3430   }   }
3431    
3432   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3433        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3434        if (!lconfig)
3435     erc = 1;
3436        else
3437     erc = checkForExtLinux(lconfig);
3438     }
3439    
3440     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3441    
3442   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3443     if (gr2c == 2) printf("grub2\n");
3444   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3445     if (erc == 2) printf("extlinux\n");
3446    
3447   return 0;   return 0;
3448      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3460  int main(int argc, const char ** argv) {
3460   if (!entry) return 0;   if (!entry) return 0;
3461   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3462    
3463   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3464   if (!line) return 0;   if (!line) return 0;
3465    
3466          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2585  int main(int argc, const char ** argv) { Line 3483  int main(int argc, const char ** argv) {
3483      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3484      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3485                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3486        if (updateKernelPath && newKernelInitrd) {
3487                if (updateInitrd(config, updateKernelPath, bootPrefix,
3488                                 newKernelInitrd)) return 1;
3489        }
3490      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3491                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3492                         extraInitrds, extraInitrdCount,
3493                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3494            
3495    
# Line 2597  int main(int argc, const char ** argv) { Line 3500  int main(int argc, const char ** argv) {
3500      }      }
3501    
3502      if (!outputFile)      if (!outputFile)
3503   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3504    
3505      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3506  }  }

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