Magellan Linux

Diff of /tags/grubby-8_10/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 1720 by niro, Sat Feb 18 00:51:28 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    #define NOOP_OPCODE 0x90
55    #define JMP_SHORT_OPCODE 0xeb
56    
57  /* comments get lumped in with indention */  /* comments get lumped in with indention */
58  struct lineElement {  struct lineElement {
59      char * item;      char * item;
60      char * indent;      char * indent;
61  };  };
62    
63  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
64         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
65         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
66        LT_KERNEL       = 1 << 2,
67        LT_INITRD       = 1 << 3,
68        LT_HYPER        = 1 << 4,
69        LT_DEFAULT      = 1 << 5,
70        LT_MBMODULE     = 1 << 6,
71        LT_ROOT         = 1 << 7,
72        LT_FALLBACK     = 1 << 8,
73        LT_KERNELARGS   = 1 << 9,
74        LT_BOOT         = 1 << 10,
75        LT_BOOTROOT     = 1 << 11,
76        LT_LBA          = 1 << 12,
77        LT_OTHER        = 1 << 13,
78        LT_GENERIC      = 1 << 14,
79        LT_ECHO    = 1 << 16,
80        LT_MENUENTRY    = 1 << 17,
81        LT_ENTRY_END    = 1 << 18,
82        LT_SET_VARIABLE = 1 << 19,
83        LT_UNKNOWN      = 1 << 20,
84    };
85    
86  struct singleLine {  struct singleLine {
87      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 102  struct singleEntry {
102    
103  #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 */
104    
105  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
106  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
107  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
108  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
109  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
110    #define NEED_MB      (1 << 4)
111    #define NEED_END     (1 << 5)
112    
113  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
114  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 74  struct keywordTypes { Line 117  struct keywordTypes {
117      char * key;      char * key;
118      enum lineType_e type;      enum lineType_e type;
119      char nextChar;      char nextChar;
120  } ;      char separatorChar;
121    };
122    
123    struct configFileInfo;
124    
125    typedef const char *(*findConfigFunc)(struct configFileInfo *);
126    typedef const int (*writeLineFunc)(struct configFileInfo *,
127     struct singleLine *line);
128    
129  struct configFileInfo {  struct configFileInfo {
130      char * defaultConfig;      char * defaultConfig;
131        findConfigFunc findConfig;
132        writeLineFunc writeLine;
133      struct keywordTypes * keywords;      struct keywordTypes * keywords;
134      int defaultIsIndex;      int defaultIsIndex;
135        int defaultIsVariable;
136      int defaultSupportSaved;      int defaultSupportSaved;
137      enum lineType_e entrySeparator;      enum lineType_e entryStart;
138        enum lineType_e entryEnd;
139      int needsBootPrefix;      int needsBootPrefix;
140      int argsInQuotes;      int argsInQuotes;
141      int maxTitleLength;      int maxTitleLength;
142      int titleBracketed;      int titleBracketed;
143        int titlePosition;
144        int mbHyperFirst;
145        int mbInitRdIsModule;
146        int mbConcatArgs;
147        int mbAllowExtraInitRds;
148  };  };
149    
150  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 153  struct keywordTypes grubKeywords[] = {
153      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
154      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
155      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
156      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
157      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
158        { "kernel",     LT_HYPER,       ' ' },
159      { NULL,    0, 0 },      { NULL,    0, 0 },
160  };  };
161    
162    const char *grubFindConfig(struct configFileInfo *cfi) {
163        static const char *configFiles[] = {
164     "/etc/grub.conf",
165     "/boot/grub/grub.conf",
166     "/boot/grub/menu.lst",
167     NULL
168        };
169        static int i = -1;
170    
171        if (i == -1) {
172     for (i = 0; configFiles[i] != NULL; i++) {
173        dbgPrintf("Checking \"%s\": ", configFiles[i]);
174        if (!access(configFiles[i], R_OK)) {
175     dbgPrintf("found\n");
176     return configFiles[i];
177        }
178        dbgPrintf("not found\n");
179     }
180        }
181        return configFiles[i];
182    }
183    
184  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
185      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
186      grubKeywords,    /* keywords */      .keywords = grubKeywords,
187      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
188      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
189      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
190      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
191      0,    /* argsInQuotes */      .mbHyperFirst = 1,
192      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
193      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
194    };
195    
196    struct keywordTypes grub2Keywords[] = {
197        { "menuentry",  LT_MENUENTRY,   ' ' },
198        { "}",          LT_ENTRY_END,   ' ' },
199        { "echo",       LT_ECHO,        ' ' },
200        { "set",        LT_SET_VARIABLE,' ', '=' },
201        { "root",       LT_BOOTROOT,    ' ' },
202        { "default",    LT_DEFAULT,     ' ' },
203        { "fallback",   LT_FALLBACK,    ' ' },
204        { "linux",      LT_KERNEL,      ' ' },
205        { "initrd",     LT_INITRD,      ' ', ' ' },
206        { "module",     LT_MBMODULE,    ' ' },
207        { "kernel",     LT_HYPER,       ' ' },
208        { NULL, 0, 0 },
209    };
210    
211    const char *grub2FindConfig(struct configFileInfo *cfi) {
212        static const char *configFiles[] = {
213     "/boot/grub/grub-efi.cfg",
214     "/boot/grub/grub.cfg",
215     NULL
216        };
217        static int i = -1;
218        static const char *grub_cfg = "/boot/grub/grub.cfg";
219    
220        if (i == -1) {
221     for (i = 0; configFiles[i] != NULL; i++) {
222        dbgPrintf("Checking \"%s\": ", configFiles[i]);
223        if (!access(configFiles[i], R_OK)) {
224     dbgPrintf("found\n");
225     return configFiles[i];
226        }
227     }
228        }
229    
230        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
231         * that isn't in grub1, and if it exists, return the config file path
232         * that they use. */
233        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
234     dbgPrintf("found\n");
235     return grub_cfg;
236        }
237    
238        dbgPrintf("not found\n");
239        return configFiles[i];
240    }
241    
242    struct configFileInfo grub2ConfigType = {
243        .findConfig = grub2FindConfig,
244        .keywords = grub2Keywords,
245        .defaultIsIndex = 1,
246        .defaultSupportSaved = 0,
247        .defaultIsVariable = 1,
248        .entryStart = LT_MENUENTRY,
249        .entryEnd = LT_ENTRY_END,
250        .titlePosition = 1,
251        .needsBootPrefix = 1,
252        .mbHyperFirst = 1,
253        .mbInitRdIsModule = 1,
254        .mbAllowExtraInitRds = 1,
255  };  };
256    
257  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 285  struct keywordTypes yabootKeywords[] = {
285      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
286      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
287      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
288      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
289      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
290      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
291      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 305  struct keywordTypes liloKeywords[] = {
305      { NULL,    0, 0 },      { NULL,    0, 0 },
306  };  };
307    
308    struct keywordTypes eliloKeywords[] = {
309        { "label",    LT_TITLE,    '=' },
310        { "root",    LT_ROOT,    '=' },
311        { "default",    LT_DEFAULT,    '=' },
312        { "image",    LT_KERNEL,    '=' },
313        { "initrd",    LT_INITRD,    '=' },
314        { "append",    LT_KERNELARGS,  '=' },
315        { "vmm",    LT_HYPER,       '=' },
316        { NULL,    0, 0 },
317    };
318    
319  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
320      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
321      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 337  struct keywordTypes ziplKeywords[] = {
337      { NULL,         0, 0 },      { NULL,         0, 0 },
338  };  };
339    
340    struct keywordTypes extlinuxKeywords[] = {
341        { "label",    LT_TITLE,    ' ' },
342        { "root",    LT_ROOT,    ' ' },
343        { "default",    LT_DEFAULT,    ' ' },
344        { "kernel",    LT_KERNEL,    ' ' },
345        { "initrd",    LT_INITRD,      ' ', ',' },
346        { "append",    LT_KERNELARGS,  ' ' },
347        { "prompt",     LT_UNKNOWN,     ' ' },
348        { NULL,    0, 0 },
349    };
350    int useextlinuxmenu;
351  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
352      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
353      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
354      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
355      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
356      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
357      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
358  };  };
359    
360  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
361      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
362      liloKeywords,    /* keywords */      .keywords = liloKeywords,
363      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
364      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
365      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
366  };  };
367    
368  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
369      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
370      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
371      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
372      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
373      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
374      1,    /* needsBootPrefix */      .maxTitleLength = 15,
375      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
376  };  };
377    
378  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
379      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
380      siloKeywords,    /* keywords */      .keywords = siloKeywords,
381      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
382      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
383      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
384      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
385  };  };
386    
387  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
388      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
389      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
390      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
391      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
392      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
393      0,    /* needsBootPrefix */  };
394      1,    /* argsInQuotes */  
395      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
396      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
397        .keywords = extlinuxKeywords,
398        .entryStart = LT_TITLE,
399        .needsBootPrefix = 1,
400        .maxTitleLength = 255,
401        .mbAllowExtraInitRds = 1,
402  };  };
403    
404  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 413  struct grubConfig {
413      struct configFileInfo * cfi;      struct configFileInfo * cfi;
414  };  };
415    
416    blkid_cache blkid;
417    
418  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
419  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
420       const char * path, const char * prefix,       const char * path, const char * prefix,
421       int * index);       int * index);
 static char * strndup(char * from, int len);  
422  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
423  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
424    struct singleLine * lineDup(struct singleLine * line);
425  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
426  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
427       struct configFileInfo * cfi);       struct configFileInfo * cfi);
428  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
429         struct configFileInfo * cfi);         struct configFileInfo * cfi);
430  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
431    static void requote(struct singleLine *line, struct configFileInfo * cfi);
432  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
433      char * to;    const char * item, int insertHere,
434      struct configFileInfo * cfi);
435      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
436      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
437      to[len] = '\0';        struct configFileInfo * cfi);
438    static enum lineType_e getTypeByKeyword(char * keyword,
439      return to;   struct configFileInfo * cfi);
440  }  static struct singleLine * getLineByType(enum lineType_e type,
441     struct singleLine * line);
442    static int checkForExtLinux(struct grubConfig * config);
443    struct singleLine * addLineTmpl(struct singleEntry * entry,
444                                    struct singleLine * tmplLine,
445                                    struct singleLine * prevLine,
446                                    const char * val,
447     struct configFileInfo * cfi);
448    struct singleLine *  addLine(struct singleEntry * entry,
449                                 struct configFileInfo * cfi,
450                                 enum lineType_e type, char * defaultIndent,
451                                 const char * val);
452    
453  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
454  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 483  static char * sdupprintf(const char *for
483      return buf;      return buf;
484  }  }
485    
486    static struct keywordTypes * getKeywordByType(enum lineType_e type,
487          struct configFileInfo * cfi) {
488        struct keywordTypes * kw;
489        for (kw = cfi->keywords; kw->key; kw++) {
490     if (kw->type == type)
491        return kw;
492        }
493        return NULL;
494    }
495    
496    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
497        struct keywordTypes *kt = getKeywordByType(type, cfi);
498        if (kt)
499     return kt->key;
500        return "unknown";
501    }
502    
503    static char * getpathbyspec(char *device) {
504        if (!blkid)
505            blkid_get_cache(&blkid, NULL);
506    
507        return blkid_get_devname(blkid, device, NULL);
508    }
509    
510    static char * getuuidbydev(char *device) {
511        if (!blkid)
512     blkid_get_cache(&blkid, NULL);
513    
514        return blkid_get_tag_value(blkid, "UUID", device);
515    }
516    
517    static enum lineType_e getTypeByKeyword(char * keyword,
518     struct configFileInfo * cfi) {
519        struct keywordTypes * kw;
520        for (kw = cfi->keywords; kw->key; kw++) {
521     if (!strcmp(keyword, kw->key))
522        return kw->type;
523        }
524        return LT_UNKNOWN;
525    }
526    
527    static struct singleLine * getLineByType(enum lineType_e type,
528     struct singleLine * line) {
529        dbgPrintf("getLineByType(%d): ", type);
530        for (; line; line = line->next) {
531     dbgPrintf("%d:%s ", line->type,
532      line->numElements ? line->elements[0].item : "(empty)");
533     if (line->type & type) break;
534        }
535        dbgPrintf(line ? "\n" : " (failed)\n");
536        return line;
537    }
538    
539  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
540      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
541          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
542          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
543              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 549  static int isBracketedTitle(struct singl
549      return 0;      return 0;
550  }  }
551    
552  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
553                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
554      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
555   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;  
556  }  }
557    
558  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 603  static void lineInit(struct singleLine *
603      line->next = NULL;      line->next = NULL;
604  }  }
605    
606    struct singleLine * lineDup(struct singleLine * line) {
607        int i;
608        struct singleLine * newLine = malloc(sizeof(*newLine));
609    
610        newLine->indent = strdup(line->indent);
611        newLine->next = NULL;
612        newLine->type = line->type;
613        newLine->numElements = line->numElements;
614        newLine->elements = malloc(sizeof(*newLine->elements) *
615           newLine->numElements);
616    
617        for (i = 0; i < newLine->numElements; i++) {
618     newLine->elements[i].indent = strdup(line->elements[i].indent);
619     newLine->elements[i].item = strdup(line->elements[i].item);
620        }
621    
622        return newLine;
623    }
624    
625  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
626      int i;      int i;
627    
# Line 414  static int lineWrite(FILE * out, struct Line 647  static int lineWrite(FILE * out, struct
647      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
648    
649   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
650   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
651        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
652      }      }
653    
654      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 667  static int getNextLine(char ** bufPtr, s
667      char * chptr;      char * chptr;
668      int elementsAlloced = 0;      int elementsAlloced = 0;
669      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
670      int first = 1;      int first = 1;
     int i;  
671    
672      lineFree(line);      lineFree(line);
673    
# Line 489  static int getNextLine(char ** bufPtr, s Line 721  static int getNextLine(char ** bufPtr, s
721      if (!line->numElements)      if (!line->numElements)
722   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
723      else {      else {
724   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
725      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;  
               
726              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
727               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
728              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 758  static int getNextLine(char ** bufPtr, s
758   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
759   line->numElements = 0;   line->numElements = 0;
760      }      }
761     } else {
762     struct keywordTypes *kw;
763    
764     kw = getKeywordByType(line->type, cfi);
765    
766     /* space isn't the only separator, we need to split
767     * elements up more
768     */
769     if (!isspace(kw->separatorChar)) {
770        int i;
771        char indent[2] = "";
772        indent[0] = kw->separatorChar;
773        for (i = 1; i < line->numElements; i++) {
774     char *p;
775     int j;
776     int numNewElements;
777    
778     numNewElements = 0;
779     p = line->elements[i].item;
780     while (*p != '\0') {
781     if (*p == kw->separatorChar)
782     numNewElements++;
783     p++;
784     }
785     if (line->numElements + numNewElements >= elementsAlloced) {
786     elementsAlloced += numNewElements + 5;
787     line->elements = realloc(line->elements,
788        sizeof(*line->elements) * elementsAlloced);
789     }
790    
791     for (j = line->numElements; j > i; j--) {
792     line->elements[j + numNewElements] = line->elements[j];
793     }
794     line->numElements += numNewElements;
795    
796     p = line->elements[i].item;
797     while (*p != '\0') {
798    
799     while (*p != kw->separatorChar && *p != '\0') p++;
800     if (*p == '\0') {
801     break;
802     }
803    
804     free(line->elements[i].indent);
805     line->elements[i].indent = strdup(indent);
806     *p++ = '\0';
807     i++;
808     line->elements[i].item = strdup(p);
809     line->elements[i].indent = strdup("");
810     p = line->elements[i].item;
811     }
812        }
813     }
814   }   }
815      }      }
816    
# Line 595  static struct grubConfig * readConfig(co Line 874  static struct grubConfig * readConfig(co
874      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
875   }   }
876    
877   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi)) {
878      sawEntry = 1;      sawEntry = 1;
879      if (!entry) {      if (!entry) {
880   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 890  static struct grubConfig * readConfig(co
890      entry->next = NULL;      entry->next = NULL;
891   }   }
892    
893   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
894        int i;
895        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
896        dbgPrintf("%s", line->indent);
897        for (i = 0; i < line->numElements; i++)
898     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
899        dbgPrintf("\n");
900        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
901        if (kwType && line->numElements == 3 &&
902        !strcmp(line->elements[1].item, kwType->key)) {
903     dbgPrintf("Line sets default config\n");
904     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
905     defaultLine = line;
906        }
907     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
908      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
909      defaultLine = line;      defaultLine = line;
910    
911            } else if (line->type == LT_KERNEL) {
912        /* if by some freak chance this is multiboot and the "module"
913         * lines came earlier in the template, make sure to use LT_HYPER
914         * instead of LT_KERNEL now
915         */
916        if (entry->multiboot)
917     line->type = LT_HYPER;
918    
919          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
920        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
921         * instead, now that we know this is a multiboot entry.
922         * This only applies to grub, but that's the only place we
923         * should find LT_MBMODULE lines anyway.
924         */
925        struct singleLine * l;
926        for (l = entry->lines; l; l = l->next) {
927     if (l->type == LT_HYPER)
928        break;
929     else if (l->type == LT_KERNEL) {
930        l->type = LT_HYPER;
931        break;
932     }
933        }
934              entry->multiboot = 1;              entry->multiboot = 1;
935    
936     } else if (line->type == LT_HYPER) {
937        entry->multiboot = 1;
938    
939   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
940      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
941      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
942    
943   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
944      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
945      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 964  static struct grubConfig * readConfig(co
964      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
965      line->elements[1].item = buf;      line->elements[1].item = buf;
966      line->numElements = 2;      line->numElements = 2;
967    
968   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
969      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
970         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 974  static struct grubConfig * readConfig(co
974   int last, len;   int last, len;
975    
976   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
977      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
978     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
979    
980   last = line->numElements - 1;   last = line->numElements - 1;
981   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
982   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
983      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
984      }      }
   
985   }   }
986    
987   /* 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 1001  static struct grubConfig * readConfig(co
1001   movedLine = 1;   movedLine = 1;
1002   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1003   }   }
1004    
1005   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1006     which was moved, drop it. */     which was moved, drop it. */
1007   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 1017  static struct grubConfig * readConfig(co
1017   entry->lines = line;   entry->lines = line;
1018      else      else
1019   last->next = line;   last->next = line;
1020        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1021    
1022        /* we could have seen this outside of an entry... if so, we
1023         * ignore it like any other line we don't grok */
1024        if (line->type == LT_ENTRY_END && sawEntry)
1025     sawEntry = 0;
1026   } else {   } else {
1027      if (!cfg->theLines)      if (!cfg->theLines)
1028   cfg->theLines = line;   cfg->theLines = line;
1029      else {      else
1030   last->next = line;   last->next = line;
1031      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1032   }   }
1033    
1034   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1036  static struct grubConfig * readConfig(co
1036    
1037      free(incoming);      free(incoming);
1038    
1039        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1040      if (defaultLine) {      if (defaultLine) {
1041   if (cfi->defaultSupportSaved &&   if (cfi->defaultIsVariable) {
1042        char *value = defaultLine->elements[2].item;
1043        while (*value && (*value == '"' || *value == '\'' ||
1044        *value == ' ' || *value == '\t'))
1045     value++;
1046        cfg->defaultImage = strtol(value, &end, 10);
1047        while (*end && (*end == '"' || *end == '\'' ||
1048        *end == ' ' || *end == '\t'))
1049     end++;
1050        if (*end) cfg->defaultImage = -1;
1051     } else if (cfi->defaultSupportSaved &&
1052   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1053      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1054   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1069  static struct grubConfig * readConfig(co
1069                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1070                  }                  }
1071   i++;   i++;
1072     entry = NULL;
1073      }      }
1074    
1075      if (entry) cfg->defaultImage = i;      if (entry){
1076            cfg->defaultImage = i;
1077        }else{
1078            cfg->defaultImage = -1;
1079        }
1080   }   }
1081        } else {
1082            cfg->defaultImage = 0;
1083      }      }
1084    
1085      return cfg;      return cfg;
# Line 751  static void writeDefault(FILE * out, cha Line 1097  static void writeDefault(FILE * out, cha
1097   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1098      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1099   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1100      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1101      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1102     cfg->defaultImage);
1103        } else {
1104     fprintf(out, "%sdefault%s%d\n", indent, separator,
1105     cfg->defaultImage);
1106        }
1107   } else {   } else {
1108      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1109    
# Line 769  static void writeDefault(FILE * out, cha Line 1120  static void writeDefault(FILE * out, cha
1120    
1121      if (!entry) return;      if (!entry) return;
1122    
1123      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1124    
1125      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1126   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1154  static int writeConfig(struct grubConfig
1154      int rc;      int rc;
1155    
1156      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1157         directory to / */         directory to the dir of the symlink */
1158      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1159      do {      do {
1160   buf = alloca(len + 1);   buf = alloca(len + 1);
1161   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1162   if (rc == len) len += 256;   if (rc == len) len += 256;
1163      } while (rc == len);      } while (rc == len);
1164            
# Line 843  static int writeConfig(struct grubConfig Line 1193  static int writeConfig(struct grubConfig
1193      }      }
1194    
1195      line = cfg->theLines;      line = cfg->theLines;
1196        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1197      while (line) {      while (line) {
1198   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1199     line->numElements == 3 &&
1200     !strcmp(line->elements[1].item, defaultKw->key)) {
1201        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1202        needs &= ~MAIN_DEFAULT;
1203     } else if (line->type == LT_DEFAULT) {
1204      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1205      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1206   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1268  static int numEntries(struct grubConfig
1268      return i;      return i;
1269  }  }
1270    
1271    static char *findDiskForRoot()
1272    {
1273        int fd;
1274        char buf[65536];
1275        char *devname;
1276        char *chptr;
1277        int rc;
1278    
1279        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1280            fprintf(stderr, "grubby: failed to open %s: %s\n",
1281                    _PATH_MOUNTED, strerror(errno));
1282            return NULL;
1283        }
1284    
1285        rc = read(fd, buf, sizeof(buf) - 1);
1286        if (rc <= 0) {
1287            fprintf(stderr, "grubby: failed to read %s: %s\n",
1288                    _PATH_MOUNTED, strerror(errno));
1289            close(fd);
1290            return NULL;
1291        }
1292        close(fd);
1293        buf[rc] = '\0';
1294        chptr = buf;
1295    
1296        while (chptr && chptr != buf+rc) {
1297            devname = chptr;
1298    
1299            /*
1300             * The first column of a mtab entry is the device, but if the entry is a
1301             * special device it won't start with /, so move on to the next line.
1302             */
1303            if (*devname != '/') {
1304                chptr = strchr(chptr, '\n');
1305                if (chptr)
1306                    chptr++;
1307                continue;
1308            }
1309    
1310            /* Seek to the next space */
1311            chptr = strchr(chptr, ' ');
1312            if (!chptr) {
1313                fprintf(stderr, "grubby: error parsing %s: %s\n",
1314                        _PATH_MOUNTED, strerror(errno));
1315                return NULL;
1316            }
1317    
1318            /*
1319             * The second column of a mtab entry is the mount point, we are looking
1320             * for '/' obviously.
1321             */
1322            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1323                /*
1324                 * Move back 2, which is the first space after the device name, set
1325                 * it to \0 so strdup will just get the devicename.
1326                 */
1327                chptr -= 2;
1328                *chptr = '\0';
1329                return strdup(devname);
1330            }
1331    
1332            /* Next line */
1333            chptr = strchr(chptr, '\n');
1334            if (chptr)
1335                chptr++;
1336        }
1337    
1338        return NULL;
1339    }
1340    
1341  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1342    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1343      struct singleLine * line;      struct singleLine * line;
1344      char * fullName;      char * fullName;
1345      int i;      int i;
     struct stat sb, sb2;  
1346      char * dev;      char * dev;
     char * end;  
1347      char * rootspec;      char * rootspec;
1348        char * rootdev;
1349    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
       
     if (!line) return 0;  
1350      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) return 0;
1351      if (line->numElements < 2) return 0;  
1352        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1353        if (!line || line->numElements < 2) return 0;
1354    
1355      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1356    
# Line 935  int suitableImage(struct singleEntry * e Line 1358  int suitableImage(struct singleEntry * e
1358        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1359      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1360      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1361              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
                                       strlen(rootspec) : 0));  
1362      if (access(fullName, R_OK)) return 0;      if (access(fullName, R_OK)) return 0;
1363    
1364      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 945  int suitableImage(struct singleEntry * e Line 1367  int suitableImage(struct singleEntry * e
1367   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1368      } else {      } else {
1369   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1370   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1371    
1372   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1373      dev = line->elements[1].item;      dev = line->elements[1].item;
1374   } else {   } else {
1375              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1376      /* 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.
1377      line = entry->lines;       */
1378        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1379    
1380              /* failed to find one */              /* failed to find one */
1381              if (!line) return 0;              if (!line) return 0;
# Line 973  int suitableImage(struct singleEntry * e Line 1391  int suitableImage(struct singleEntry * e
1391   }   }
1392      }      }
1393    
1394      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1395   dev += 6;      if (!dev)
1396            return 0;
1397   /* check which device has this label */  
1398   dev = get_spec_by_volume_label(dev, &i, &i);      rootdev = findDiskForRoot();
1399   if (!dev) return 0;      if (!rootdev)
1400     return 0;
1401    
1402        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1403            free(rootdev);
1404            return 0;
1405      }      }
1406    
1407      if (*dev == '/') {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1408   if (stat(dev, &sb))   free(rootdev);
1409      return 0;          return 0;
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1410      }      }
     stat("/", &sb2);  
1411    
1412      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1413    
1414      return 1;      return 1;
1415  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1453  struct singleEntry * findEntryByPath(str
1453   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1454   if (!entry) return NULL;   if (!entry) return NULL;
1455    
1456   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1457   if (!line) return NULL;   if (!line) return NULL;
1458    
1459   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1495  struct singleEntry * findEntryByPath(str
1495      kernel += 6;      kernel += 6;
1496   }   }
1497    
1498   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1499      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1500    
1501        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1502    
1503      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1504                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1505          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1506                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1507                              kernel + strlen(prefix)))       checkType, line);
1508                      break;   if (!line) break;  /* not found in this entry */
1509              }  
1510                 if (line && line->numElements >= 2) {
1511              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1512              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1513                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1514                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1515                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1516                      if (!strcmp(line->elements[1].item  +   }
1517                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1518    
1519      i++;      /* make sure this entry has a kernel identifier; this skips
1520         * non-Linux boot entries (could find netbsd etc, though, which is
1521         * unfortunate)
1522         */
1523        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1524     break; /* found 'im! */
1525   }   }
1526    
1527   if (index) *index = i;   if (index) *index = i;
1528      }      }
1529    
     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);  
     }  
   
1530      return entry;      return entry;
1531  }  }
1532    
# Line 1286  void displayEntry(struct singleEntry * e Line 1691  void displayEntry(struct singleEntry * e
1691      char * root = NULL;      char * root = NULL;
1692      int i;      int i;
1693    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1694      printf("index=%d\n", index);      printf("index=%d\n", index);
1695    
1696        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1697        if (!line) {
1698            printf("non linux entry\n");
1699            return;
1700        }
1701    
1702      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1703    
1704      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1716  void displayEntry(struct singleEntry * e
1716   }   }
1717   printf("\"\n");   printf("\"\n");
1718      } else {      } else {
1719   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1720   if (line) {   if (line) {
1721      char * s;      char * s;
1722    
# Line 1334  void displayEntry(struct singleEntry * e Line 1740  void displayEntry(struct singleEntry * e
1740      }      }
1741    
1742      if (!root) {      if (!root) {
1743   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1744   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1745      root=line->elements[1].item;      root=line->elements[1].item;
1746      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1755  void displayEntry(struct singleEntry * e
1755   printf("root=%s\n", s);   printf("root=%s\n", s);
1756      }      }
1757    
1758      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1759    
1760      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1761   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1772  int parseSysconfigGrub(int * lbaPtr, cha
1772      char * start;      char * start;
1773      char * param;      char * param;
1774    
1775      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1776      if (!in) return 1;      if (!in) return 1;
1777    
1778      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1834  int displayInfo(struct grubConfig * conf
1834   return 1;   return 1;
1835      }      }
1836    
1837      /* 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
1838         be a better way */         be a better way */
1839      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1840   dumpSysconfigGrub();   dumpSysconfigGrub();
1841      } else {      } else {
1842   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1843   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1844      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1845   }   }
1846    
1847   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1848   if (line) printf("lba\n");   if (line) printf("lba\n");
1849      }      }
1850    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1859  int displayInfo(struct grubConfig * conf
1859      return 0;      return 0;
1860  }  }
1861    
1862    struct singleLine * addLineTmpl(struct singleEntry * entry,
1863     struct singleLine * tmplLine,
1864     struct singleLine * prevLine,
1865     const char * val,
1866     struct configFileInfo * cfi)
1867    {
1868        struct singleLine * newLine = lineDup(tmplLine);
1869    
1870        if (val) {
1871     /* override the inherited value with our own.
1872     * This is a little weak because it only applies to elements[1]
1873     */
1874     if (newLine->numElements > 1)
1875        removeElement(newLine, 1);
1876     insertElement(newLine, val, 1, cfi);
1877    
1878     /* but try to keep the rootspec from the template... sigh */
1879     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1880        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1881        if (rootspec != NULL) {
1882     free(newLine->elements[1].item);
1883     newLine->elements[1].item =
1884        sdupprintf("%s%s", rootspec, val);
1885        }
1886     }
1887        }
1888    
1889        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1890          newLine->elements[0].item : "");
1891    
1892        if (!entry->lines) {
1893     /* first one on the list */
1894     entry->lines = newLine;
1895        } else if (prevLine) {
1896     /* add after prevLine */
1897     newLine->next = prevLine->next;
1898     prevLine->next = newLine;
1899        }
1900    
1901        return newLine;
1902    }
1903    
1904  /* val may be NULL */  /* val may be NULL */
1905  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1906       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1907       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1908       char * val) {       const char * val) {
1909      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1910      int i;      struct keywordTypes * kw;
1911        struct singleLine tmpl;
1912    
1913      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1914   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1915      if (type != LT_TITLE || !cfi->titleBracketed)       */
1916          if (!cfi->keywords[i].key) abort();  
1917        if (type == LT_TITLE && cfi->titleBracketed) {
1918     /* we're doing a bracketed title (zipl) */
1919     tmpl.type = type;
1920     tmpl.numElements = 1;
1921     tmpl.elements = alloca(sizeof(*tmpl.elements));
1922     tmpl.elements[0].item = alloca(strlen(val)+3);
1923     sprintf(tmpl.elements[0].item, "[%s]", val);
1924     tmpl.elements[0].indent = "";
1925     val = NULL;
1926        } else if (type == LT_MENUENTRY) {
1927     char *lineend = "--class gnu-linux --class gnu --class os {";
1928     if (!val) {
1929        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
1930        abort();
1931     }
1932     kw = getKeywordByType(type, cfi);
1933     if (!kw) {
1934        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1935        abort();
1936     }
1937     tmpl.indent = "";
1938     tmpl.type = type;
1939     tmpl.numElements = 3;
1940     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1941     tmpl.elements[0].item = kw->key;
1942     tmpl.elements[0].indent = alloca(2);
1943     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1944     tmpl.elements[1].item = (char *)val;
1945     tmpl.elements[1].indent = alloca(2);
1946     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
1947     tmpl.elements[2].item = alloca(strlen(lineend)+1);
1948     strcpy(tmpl.elements[2].item, lineend);
1949     tmpl.elements[2].indent = "";
1950        } else {
1951     kw = getKeywordByType(type, cfi);
1952     if (!kw) {
1953        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1954        abort();
1955     }
1956     tmpl.type = type;
1957     tmpl.numElements = val ? 2 : 1;
1958     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1959     tmpl.elements[0].item = kw->key;
1960     tmpl.elements[0].indent = alloca(2);
1961     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1962     if (val) {
1963        tmpl.elements[1].item = (char *)val;
1964        tmpl.elements[1].indent = "";
1965     }
1966        }
1967    
1968      /* 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
1969         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1970         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
1971         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1972         differently from the rest) */         differently from the rest) */
1973      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1974   line = entry->lines;   if (line->numElements) prev = line;
1975   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1976   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;  
1977      }      }
1978    
1979      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
1980          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
1981          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
1982          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
1983          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
1984          line->elements[0].indent = malloc(2);   else
1985          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
1986          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
1987             if (menuEntry)
1988          if (val) {      tmpl.indent = "\t";
1989              line->elements[1].item = val;   else if (prev == entry->lines)
1990              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
1991          }   else
1992      } 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("");  
1993      }      }
1994    
1995      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1996  }  }
1997    
1998  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2017  void removeLine(struct singleEntry * ent
2017      free(line);      free(line);
2018  }  }
2019    
2020    static int isquote(char q)
2021    {
2022        if (q == '\'' || q == '\"')
2023     return 1;
2024        return 0;
2025    }
2026    
2027    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2028    {
2029        struct singleLine newLine = {
2030     .indent = tmplLine->indent,
2031     .type = tmplLine->type,
2032     .next = tmplLine->next,
2033        };
2034        int firstQuotedItem = -1;
2035        int quoteLen = 0;
2036        int j;
2037        int element = 0;
2038        char *c;
2039    
2040        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2041        strcpy(c, tmplLine->elements[0].item);
2042        insertElement(&newLine, c, element++, cfi);
2043        free(c);
2044        c = NULL;
2045    
2046        for (j = 1; j < tmplLine->numElements; j++) {
2047     if (firstQuotedItem == -1) {
2048        quoteLen += strlen(tmplLine->elements[j].item);
2049        
2050        if (isquote(tmplLine->elements[j].item[0])) {
2051     firstQuotedItem = j;
2052            quoteLen += strlen(tmplLine->elements[j].indent);
2053        } else {
2054     c = malloc(quoteLen + 1);
2055     strcpy(c, tmplLine->elements[j].item);
2056     insertElement(&newLine, c, element++, cfi);
2057     free(c);
2058     quoteLen = 0;
2059        }
2060     } else {
2061        int itemlen = strlen(tmplLine->elements[j].item);
2062        quoteLen += itemlen;
2063        quoteLen += strlen(tmplLine->elements[j].indent);
2064        
2065        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2066     c = malloc(quoteLen + 1);
2067     c[0] = '\0';
2068     for (int i = firstQuotedItem; i < j+1; i++) {
2069        strcat(c, tmplLine->elements[i].item);
2070        strcat(c, tmplLine->elements[i].indent);
2071     }
2072     insertElement(&newLine, c, element++, cfi);
2073     free(c);
2074    
2075     firstQuotedItem = -1;
2076     quoteLen = 0;
2077        }
2078     }
2079        }
2080        while (tmplLine->numElements)
2081     removeElement(tmplLine, 0);
2082        if (tmplLine->elements)
2083     free(tmplLine->elements);
2084    
2085        tmplLine->numElements = newLine.numElements;
2086        tmplLine->elements = newLine.elements;
2087    }
2088    
2089    static void insertElement(struct singleLine * line,
2090      const char * item, int insertHere,
2091      struct configFileInfo * cfi)
2092    {
2093        struct keywordTypes * kw;
2094        char indent[2] = "";
2095    
2096        /* sanity check */
2097        if (insertHere > line->numElements) {
2098     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2099      insertHere, line->numElements);
2100     insertHere = line->numElements;
2101        }
2102    
2103        line->elements = realloc(line->elements, (line->numElements + 1) *
2104         sizeof(*line->elements));
2105        memmove(&line->elements[insertHere+1],
2106        &line->elements[insertHere],
2107        (line->numElements - insertHere) *
2108        sizeof(*line->elements));
2109        line->elements[insertHere].item = strdup(item);
2110    
2111        kw = getKeywordByType(line->type, cfi);
2112    
2113        if (line->numElements == 0) {
2114     indent[0] = '\0';
2115        } else if (insertHere == 0) {
2116     indent[0] = kw->nextChar;
2117        } else if (kw->separatorChar != '\0') {
2118     indent[0] = kw->separatorChar;
2119        } else {
2120     indent[0] = ' ';
2121        }
2122    
2123        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2124     /* move the end-of-line forward */
2125     line->elements[insertHere].indent =
2126        line->elements[insertHere-1].indent;
2127     line->elements[insertHere-1].indent = strdup(indent);
2128        } else {
2129     line->elements[insertHere].indent = strdup(indent);
2130        }
2131    
2132        line->numElements++;
2133    
2134        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2135          line->elements[0].item,
2136          line->elements[insertHere].item,
2137          line->elements[insertHere].indent,
2138          insertHere);
2139    }
2140    
2141    static void removeElement(struct singleLine * line, int removeHere) {
2142        int i;
2143    
2144        /* sanity check */
2145        if (removeHere >= line->numElements) return;
2146    
2147        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2148          removeHere, line->elements[removeHere].item);
2149    
2150        free(line->elements[removeHere].item);
2151    
2152        if (removeHere > 1) {
2153     /* previous argument gets this argument's post-indentation */
2154     free(line->elements[removeHere-1].indent);
2155     line->elements[removeHere-1].indent =
2156        line->elements[removeHere].indent;
2157        } else {
2158     free(line->elements[removeHere].indent);
2159        }
2160    
2161        /* now collapse the array, but don't bother to realloc smaller */
2162        for (i = removeHere; i < line->numElements - 1; i++)
2163     line->elements[i] = line->elements[i + 1];
2164    
2165        line->numElements--;
2166    }
2167    
2168  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2169      char * first, * second;      char * first, * second;
2170      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2187  int updateActualImage(struct grubConfig
2187      struct singleEntry * entry;      struct singleEntry * entry;
2188      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2189      int index = 0;      int index = 0;
2190      int i, j, k;      int i, k;
2191      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2192      const char ** arg;      const char ** arg;
2193      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2194      int firstElement;      int firstElement;
2195      int *usedElements, *usedArgs;      int *usedElements;
2196        int doreplace;
2197    
2198      if (!image) return 0;      if (!image) return 0;
2199    
# Line 1609  int updateActualImage(struct grubConfig Line 2220  int updateActualImage(struct grubConfig
2220   }   }
2221      }      }
2222    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2223    
2224      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2225   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2226    
2227      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2228   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2229    
2230      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2231    
2232      k = 0;   if (multibootArgs && !entry->multiboot)
2233      for (arg = newArgs; *arg; arg++)      continue;
2234          k++;  
2235      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2236     * LT_KERNELARGS, use that.  Otherwise use
2237     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2238     */
2239     if (useKernelArgs) {
2240        line = getLineByType(LT_KERNELARGS, entry->lines);
2241        if (!line) {
2242     /* no LT_KERNELARGS, need to add it */
2243     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2244           cfg->secondaryIndent, NULL);
2245        }
2246        firstElement = 1;
2247    
2248      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2249   index++;      line = getLineByType(LT_HYPER, entry->lines);
2250        if (!line) {
2251     /* a multiboot entry without LT_HYPER? */
2252     continue;
2253        }
2254        firstElement = 2;
2255    
2256   line = entry->lines;   } else {
2257   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2258   if (!line) continue;      if (!line) {
2259   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2260     continue;
2261          if (entry->multiboot && !multibootArgs) {      }
2262              /* 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;  
2263   }   }
2264    
2265   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2266      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2267      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2268     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2269        /* this is a multiboot entry, make sure there's
2270         * -- on the args line
2271         */
2272        for (i = firstElement; i < line->numElements; i++) {
2273     if (!strcmp(line->elements[i].item, "--"))
2274        break;
2275        }
2276        if (i == line->numElements) {
2277     /* assume all existing args are kernel args,
2278     * prepend -- to make it official
2279     */
2280     insertElement(line, "--", firstElement, cfg->cfi);
2281     i = firstElement;
2282        }
2283        if (!multibootArgs) {
2284     /* kernel args start after the -- */
2285     firstElement = i + 1;
2286        }
2287     } else if (cfg->cfi->mbConcatArgs) {
2288        /* this is a non-multiboot entry, remove hyper args */
2289        for (i = firstElement; i < line->numElements; i++) {
2290     if (!strcmp(line->elements[i].item, "--"))
2291        break;
2292        }
2293        if (i < line->numElements) {
2294     /* remove args up to -- */
2295     while (strcmp(line->elements[firstElement].item, "--"))
2296        removeElement(line, firstElement);
2297     /* remove -- */
2298     removeElement(line, firstElement);
2299        }
2300   }   }
2301    
2302          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2303    
2304          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2305   for (arg = newArgs; *arg; arg++) {  
2306              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2307      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2308     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2309        !strcmp(line->elements[i].item, "--"))
2310     {
2311        /* reached the end of hyper args, insert here */
2312        doreplace = 0;
2313        break;  
2314     }
2315                  if (usedElements[i])                  if (usedElements[i])
2316                      continue;                      continue;
2317   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2318                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2319      break;      break;
2320                  }                  }
2321              }              }
     chptr = strchr(*arg, '=');  
2322    
2323      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2324   /* replace */   /* direct replacement */
2325   free(line->elements[i].item);   free(line->elements[i].item);
2326   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("");  
  }  
2327    
2328   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2329   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2330      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2331   /* append */   if (rootLine) {
2332   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2333   (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(" ");  
2334   } else {   } else {
2335      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2336         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2337   }   }
2338        }
2339    
2340   line->numElements++;      else {
2341     /* insert/append */
2342     insertElement(line, *arg, i, cfg->cfi);
2343     usedElements = realloc(usedElements, line->numElements *
2344           sizeof(*usedElements));
2345     memmove(&usedElements[i + 1], &usedElements[i],
2346     line->numElements - i - 1);
2347     usedElements[i] = 1;
2348    
2349   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2350     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2351     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2352   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2353      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2354      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2355   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2356   }   }
2357      }      }
             k++;  
2358   }   }
2359    
2360          free(usedElements);          free(usedElements);
2361    
  /* 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? */  
2362   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2363      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2364   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2365        !strcmp(line->elements[i].item, "--"))
2366        /* reached the end of hyper args, stop here */
2367        break;
2368     if (!argMatch(line->elements[i].item, *arg)) {
2369        removeElement(line, i);
2370      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;  
2371   }   }
2372        }
2373   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2374        if (useRoot && !strncmp(*arg, "root=", 5)) {
2375   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2376      line->elements[j - 1] = line->elements[j];   if (rootLine)
2377        removeLine(entry, rootLine);
  line->numElements--;  
2378      }      }
2379   }   }
2380    
# Line 1760  int updateActualImage(struct grubConfig Line 2385  int updateActualImage(struct grubConfig
2385   }   }
2386      }      }
2387    
     free(usedArgs);  
2388      free(newArgs);      free(newArgs);
2389      free(oldArgs);      free(oldArgs);
2390    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2410  int updateImage(struct grubConfig * cfg,
2410      return rc;      return rc;
2411  }  }
2412    
2413    int updateInitrd(struct grubConfig * cfg, const char * image,
2414                     const char * prefix, const char * initrd) {
2415        struct singleEntry * entry;
2416        struct singleLine * line, * kernelLine, *endLine = NULL;
2417        int index = 0;
2418    
2419        if (!image) return 0;
2420    
2421        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2422            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2423            if (!kernelLine) continue;
2424    
2425            line = getLineByType(LT_INITRD, entry->lines);
2426            if (line)
2427                removeLine(entry, line);
2428            if (prefix) {
2429                int prefixLen = strlen(prefix);
2430                if (!strncmp(initrd, prefix, prefixLen))
2431                    initrd += prefixLen;
2432            }
2433     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2434     if (endLine)
2435        removeLine(entry, endLine);
2436            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2437            if (!line)
2438        return 1;
2439     if (endLine) {
2440        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2441                if (!line)
2442     return 1;
2443     }
2444    
2445            break;
2446        }
2447    
2448        return 0;
2449    }
2450    
2451  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2452      int fd;      int fd;
2453      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2471  int checkDeviceBootloader(const char * d
2471      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2472   return 0;   return 0;
2473    
2474      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2475   offset = boot[2] + 2;   offset = boot[2] + 2;
2476      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2477   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2478      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2479   offset = boot[1] + 2;        offset = boot[1] + 2;
2480            /*
2481     * it looks like grub, when copying stage1 into the mbr, patches stage1
2482     * right after the JMP location, replacing other instructions such as
2483     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2484     * different bytes.
2485     */
2486          if ((bootSect[offset + 1] == NOOP_OPCODE)
2487      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2488     offset = offset + 3;
2489          }
2490      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2491   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2492      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2628  int checkForLilo(struct grubConfig * con
2628      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2629  }  }
2630    
2631    int checkForGrub2(struct grubConfig * config) {
2632        if (!access("/etc/grub.d/", R_OK))
2633     return 2;
2634    
2635        return 1;
2636    }
2637    
2638  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2639      int fd;      int fd;
2640      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2655  int checkForGrub(struct grubConfig * con
2655      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2656   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2657   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2658     close(fd);
2659     return 1;
2660        }
2661        close(fd);
2662    
2663        return checkDeviceBootloader(boot, bootSect);
2664    }
2665    
2666    int checkForExtLinux(struct grubConfig * config) {
2667        int fd;
2668        unsigned char bootSect[512];
2669        char * boot;
2670        char executable[] = "/boot/extlinux/extlinux";
2671    
2672        printf("entered: checkForExtLinux()\n");
2673    
2674        if (parseSysconfigGrub(NULL, &boot))
2675     return 0;
2676    
2677        /* assume grub is not installed -- not an error condition */
2678        if (!boot)
2679     return 0;
2680    
2681        fd = open(executable, O_RDONLY);
2682        if (fd < 0)
2683     /* this doesn't exist if grub hasn't been installed */
2684     return 0;
2685    
2686        if (read(fd, bootSect, 512) != 512) {
2687     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2688     executable, strerror(errno));
2689   return 1;   return 1;
2690      }      }
2691      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2704  static char * getRootSpecifier(char * st
2704      return rootspec;      return rootspec;
2705  }  }
2706    
2707    static char * getInitrdVal(struct grubConfig * config,
2708       const char * prefix, struct singleLine *tmplLine,
2709       const char * newKernelInitrd,
2710       char ** extraInitrds, int extraInitrdCount)
2711    {
2712        char *initrdVal, *end;
2713        int i;
2714        size_t totalSize;
2715        size_t prefixLen;
2716        char separatorChar;
2717    
2718        prefixLen = strlen(prefix);
2719        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2720    
2721        for (i = 0; i < extraInitrdCount; i++) {
2722     totalSize += sizeof(separatorChar);
2723     totalSize += strlen(extraInitrds[i]) - prefixLen;
2724        }
2725    
2726        initrdVal = end = malloc(totalSize);
2727    
2728        end = stpcpy (end, newKernelInitrd + prefixLen);
2729    
2730        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2731        for (i = 0; i < extraInitrdCount; i++) {
2732     const char *extraInitrd;
2733     int j;
2734    
2735     extraInitrd = extraInitrds[i] + prefixLen;
2736     /* Don't add entries that are already there */
2737     if (tmplLine != NULL) {
2738        for (j = 2; j < tmplLine->numElements; j++)
2739     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2740        break;
2741    
2742        if (j != tmplLine->numElements)
2743     continue;
2744     }
2745    
2746     *end++ = separatorChar;
2747     end = stpcpy(end, extraInitrd);
2748        }
2749    
2750        return initrdVal;
2751    }
2752    
2753  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2754           const char * prefix,           const char * prefix,
2755   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2756   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2757     char ** extraInitrds, int extraInitrdCount,
2758                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2759      struct singleEntry * new;      struct singleEntry * new;
2760      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2761      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2762      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2763    
2764      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2765    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2789  int addNewKernel(struct grubConfig * con
2789      config->entries = new;      config->entries = new;
2790    
2791      /* copy/update from the template */      /* copy/update from the template */
2792      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2793        if (newKernelInitrd)
2794     needs |= NEED_INITRD;
2795      if (newMBKernel) {      if (newMBKernel) {
2796          needs |= KERNEL_MB;          needs |= NEED_MB;
2797          new->multiboot = 1;          new->multiboot = 1;
2798      }      }
2799    
2800      if (template) {      if (template) {
2801   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2802      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2803      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2804   indent = tmplLine->indent;   {
2805        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2806    
2807      /* skip comments */      /* skip comments */
2808      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2809      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2810      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2811    
2812      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2813      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2814     if (!template->multiboot && (needs & NEED_MB)) {
2815              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2816                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2817                  struct singleLine *l;       * hypervisor at the same time.
2818                  needs &= ~ KERNEL_MB;       */
2819        if (config->cfi->mbHyperFirst) {
2820                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2821                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2822                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2823                      newMBKernel + strlen(prefix));
2824                  tmplLine = lastLine;   /* set up for adding the kernel line */
2825                  if (!new->lines) {   free(tmplLine->indent);
2826                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2827                  } else {   needs &= ~NEED_MB;
2828                      newLine->next = l;      }
2829                      newLine = l;      if (needs & NEED_KERNEL) {
2830                  }   /* use addLineTmpl to preserve line elements,
2831                  continue;   * otherwise we could just call addLine.  Unfortunately
2832              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2833                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2834                  continue; /* don't need multiboot kernel here */   * change below.
2835              }   */
2836     struct keywordTypes * mbm_kw =
2837        getKeywordByType(LT_MBMODULE, config->cfi);
2838     if (mbm_kw) {
2839        tmplLine->type = LT_MBMODULE;
2840        free(tmplLine->elements[0].item);
2841        tmplLine->elements[0].item = strdup(mbm_kw->key);
2842     }
2843     newLine = addLineTmpl(new, tmplLine, newLine,
2844          newKernelPath + strlen(prefix), config->cfi);
2845     needs &= ~NEED_KERNEL;
2846        }
2847        if (needs & NEED_MB) { /* !mbHyperFirst */
2848     newLine = addLine(new, config->cfi, LT_HYPER,
2849      config->secondaryIndent,
2850      newMBKernel + strlen(prefix));
2851     needs &= ~NEED_MB;
2852        }
2853     } else if (needs & NEED_KERNEL) {
2854        newLine = addLineTmpl(new, tmplLine, newLine,
2855      newKernelPath + strlen(prefix), config->cfi);
2856        needs &= ~NEED_KERNEL;
2857     }
2858    
2859      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2860   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2861   new->lines = newLine;   if (needs & NEED_MB) {
2862      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2863   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2864   newLine = newLine->next;      needs &= ~NEED_MB;
2865      }   }
2866    
2867        } else if (tmplLine->type == LT_MBMODULE &&
2868           tmplLine->numElements >= 2) {
2869     if (new->multiboot) {
2870        if (needs & NEED_KERNEL) {
2871     newLine = addLineTmpl(new, tmplLine, newLine,
2872          newKernelPath +
2873          strlen(prefix), config->cfi);
2874     needs &= ~NEED_KERNEL;
2875        } else if (config->cfi->mbInitRdIsModule &&
2876           (needs & NEED_INITRD)) {
2877     char *initrdVal;
2878     initrdVal = getInitrdVal(config, prefix, tmplLine,
2879     newKernelInitrd, extraInitrds,
2880     extraInitrdCount);
2881     newLine = addLineTmpl(new, tmplLine, newLine,
2882          initrdVal, config->cfi);
2883     free(initrdVal);
2884     needs &= ~NEED_INITRD;
2885        }
2886     } else if (needs & NEED_KERNEL) {
2887        /* template is multi but new is not,
2888         * insert the kernel in the first module slot
2889         */
2890        tmplLine->type = LT_KERNEL;
2891        free(tmplLine->elements[0].item);
2892        tmplLine->elements[0].item =
2893     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2894        newLine = addLineTmpl(new, tmplLine, newLine,
2895      newKernelPath + strlen(prefix), config->cfi);
2896        needs &= ~NEED_KERNEL;
2897     } else if (needs & NEED_INITRD) {
2898        char *initrdVal;
2899        /* template is multi but new is not,
2900         * insert the initrd in the second module slot
2901         */
2902        tmplLine->type = LT_INITRD;
2903        free(tmplLine->elements[0].item);
2904        tmplLine->elements[0].item =
2905     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2906        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2907        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2908        free(initrdVal);
2909        needs &= ~NEED_INITRD;
2910     }
2911    
     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));  
                 }  
2912      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2913      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2914   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2915   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2916                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2917                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2918                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2919                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2920                  }       */
2921                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2922                  if (rootspec != NULL) {   char *initrdVal;
2923                      newLine->elements[1].item = sdupprintf("%s%s",  
2924                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2925                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2926                                                             strlen(prefix));    config->secondaryIndent,
2927                  } else {    initrdVal);
2928                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2929                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2930                  }      }
2931              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2932                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2933   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2934                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2935                      free(newLine->elements[0].item);      free(initrdVal);
2936                      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);  
2937   }   }
2938    
2939   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
2940   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
2941   newLine->numElements = 2;   requote(tmplLine, config->cfi);
2942     char *nkt = malloc(strlen(newKernelTitle)+3);
2943     strcpy(nkt, "'");
2944     strcat(nkt, newKernelTitle);
2945     strcat(nkt, "'");
2946     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
2947     free(nkt);
2948     needs &= ~NEED_TITLE;
2949      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2950                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2951                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2952                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2953                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2954                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2955                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2956                                             newLine->numElements);     config->cfi->titleBracketed) {
2957        /* addLineTmpl doesn't handle titleBracketed */
2958                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2959                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2960                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2961                  newLine->numElements = 1;   }
2962              }      } else if (tmplLine->type == LT_ECHO) {
2963        requote(tmplLine, config->cfi);
2964        if (tmplLine->numElements > 1 &&
2965        strstr(tmplLine->elements[1].item, "'Loading Linux ")) {
2966     char *prefix = "'Loading ";
2967     char *newTitle = malloc(strlen(prefix) +
2968     strlen(newKernelTitle) + 2);
2969    
2970     strcpy(newTitle, prefix);
2971     strcat(newTitle, newKernelTitle);
2972     strcat(newTitle, "'");
2973     newLine = addLine(new, config->cfi, LT_ECHO,
2974     tmplLine->indent, newTitle);
2975     free(newTitle);
2976        } else {
2977     /* pass through other lines from the template */
2978     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
2979     config->cfi);
2980        }
2981        } else {
2982     /* pass through other lines from the template */
2983     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2984        }
2985   }   }
2986    
2987      } else {      } else {
2988   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2989      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2990     */
2991     switch (config->cfi->entryStart) {
2992        case LT_KERNEL:
2993     if (new->multiboot && config->cfi->mbHyperFirst) {
2994        /* fall through to LT_HYPER */
2995     } else {
2996        newLine = addLine(new, config->cfi, LT_KERNEL,
2997          config->primaryIndent,
2998          newKernelPath + strlen(prefix));
2999        needs &= ~NEED_KERNEL;
3000        break;
3001     }
3002    
3003        case LT_HYPER:
3004     newLine = addLine(new, config->cfi, LT_HYPER,
3005      config->primaryIndent,
3006      newMBKernel + strlen(prefix));
3007     needs &= ~NEED_MB;
3008   break;   break;
         }  
3009    
3010   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3011      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3012       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3013       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3014      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3015       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3016      default:        config->primaryIndent, nkt);
3017                  /* zipl strikes again */   free(nkt);
3018                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3019                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3020                      chptr = newKernelTitle;   break;
3021                      type = LT_TITLE;      }
3022                      break;      case LT_TITLE:
3023                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3024                      abort();   char * templabel;
3025                  }   int x = 0, y = 0;
3026   }  
3027     templabel = strdup(newKernelTitle);
3028     while( templabel[x]){
3029     if( templabel[x] == ' ' ){
3030     y = x;
3031     while( templabel[y] ){
3032     templabel[y] = templabel[y+1];
3033     y++;
3034     }
3035     }
3036     x++;
3037     }
3038     newLine = addLine(new, config->cfi, LT_TITLE,
3039      config->primaryIndent, templabel);
3040     free(templabel);
3041     }else{
3042     newLine = addLine(new, config->cfi, LT_TITLE,
3043      config->primaryIndent, newKernelTitle);
3044     }
3045     needs &= ~NEED_TITLE;
3046     break;
3047    
3048   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3049   new->lines = newLine;   abort();
3050     }
3051      }      }
3052    
3053      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3054          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3055              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3056                                config->secondaryIndent,       */
3057                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3058          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3059              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3060                                config->secondaryIndent,    newKernelTitle);
3061                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3062          /* don't need to check for title as it's guaranteed to have been      }
3063           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3064           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3065          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3066              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3067                                config->secondaryIndent,   needs &= ~NEED_MB;
3068                                newKernelInitrd + strlen(prefix));      }
3069      } else {      if (needs & NEED_KERNEL) {
3070          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3071              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3072                                config->secondaryIndent,        config->cfi)) ?
3073                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3074          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3075              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3076                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3077                                newKernelTitle);      }
3078          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3079              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3080                                config->secondaryIndent,    config->secondaryIndent,
3081                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3082     needs &= ~NEED_MB;
3083        }
3084        if (needs & NEED_INITRD) {
3085     char *initrdVal;
3086     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3087     newLine = addLine(new, config->cfi,
3088      (new->multiboot && getKeywordByType(LT_MBMODULE,
3089          config->cfi)) ?
3090      LT_MBMODULE : LT_INITRD,
3091      config->secondaryIndent,
3092      initrdVal);
3093     free(initrdVal);
3094     needs &= ~NEED_INITRD;
3095        }
3096        if (needs & NEED_END) {
3097     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3098     config->secondaryIndent, NULL);
3099     needs &= ~NEED_END;
3100        }
3101    
3102        if (needs) {
3103     printf(_("grubby: needs=%d, aborting\n"), needs);
3104     abort();
3105      }      }
3106    
3107      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3110  int addNewKernel(struct grubConfig * con
3110      return 0;      return 0;
3111  }  }
3112    
3113    static void traceback(int signum)
3114    {
3115        void *array[40];
3116        size_t size;
3117    
3118        signal(SIGSEGV, SIG_DFL);
3119        memset(array, '\0', sizeof (array));
3120        size = backtrace(array, 40);
3121    
3122        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3123                (unsigned long)size);
3124        backtrace_symbols_fd(array, size, STDERR_FILENO);
3125        exit(1);
3126    }
3127    
3128  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3129      poptContext optCon;      poptContext optCon;
3130      char * grubConfig = NULL;      const char * grubConfig = NULL;
3131      char * outputFile = NULL;      char * outputFile = NULL;
3132      int arg = 0;      int arg = 0;
3133      int flags = 0;      int flags = 0;
3134      int badImageOkay = 0;      int badImageOkay = 0;
3135        int configureGrub2 = 0;
3136      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3137      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3138        int configureExtLinux = 0;
3139      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3140        int extraInitrdCount = 0;
3141      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3142      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3143      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3153  int main(int argc, const char ** argv) {
3153      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3154      char * removeArgs = NULL;      char * removeArgs = NULL;
3155      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3156        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3157      const char * chptr = NULL;      const char * chptr = NULL;
3158      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3159      struct grubConfig * config;      struct grubConfig * config;
3160      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3161      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3162      int displayDefault = 0;      int displayDefault = 0;
3163        int displayDefaultIndex = 0;
3164      struct poptOption options[] = {      struct poptOption options[] = {
3165   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3166      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2337  int main(int argc, const char ** argv) { Line 3193  int main(int argc, const char ** argv) {
3193        "template"), NULL },        "template"), NULL },
3194   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3195      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3196     { "default-index", 0, 0, &displayDefaultIndex, 0,
3197        _("display the index of the default kernel") },
3198   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3199      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3200     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3201        _("configure extlinux bootloader (from syslinux)") },
3202   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3203      _("configure grub bootloader") },      _("configure grub bootloader") },
3204     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3205        _("configure grub2 bootloader") },
3206   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3207      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3208      _("kernel-path") },      _("kernel-path") },
3209   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3210      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3211     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3212        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3213   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3214      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3215   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3246  int main(int argc, const char ** argv) {
3246   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3247      };      };
3248    
3249        useextlinuxmenu=0;
3250    
3251        signal(SIGSEGV, traceback);
3252    
3253      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3254      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3255    
# Line 2391  int main(int argc, const char ** argv) { Line 3259  int main(int argc, const char ** argv) {
3259      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3260      exit(0);      exit(0);
3261      break;      break;
3262      case 'i':
3263        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3264         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3265        } else {
3266     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3267     return 1;
3268        }
3269        break;
3270   }   }
3271      }      }
3272    
# Line 2406  int main(int argc, const char ** argv) { Line 3282  int main(int argc, const char ** argv) {
3282   return 1;   return 1;
3283      }      }
3284    
3285      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3286   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3287     configureExtLinux ) > 1) {
3288   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3289   return 1;   return 1;
3290      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3291   fprintf(stderr,   fprintf(stderr,
3292      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3293   return 1;   return 1;
3294        } else if (configureGrub2) {
3295     cfi = &grub2ConfigType;
3296      } else if (configureLilo) {      } else if (configureLilo) {
3297   cfi = &liloConfigType;   cfi = &liloConfigType;
3298      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3305  int main(int argc, const char ** argv) {
3305          cfi = &siloConfigType;          cfi = &siloConfigType;
3306      } else if (configureZipl) {      } else if (configureZipl) {
3307          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3308        } else if (configureExtLinux) {
3309     cfi = &extlinuxConfigType;
3310     useextlinuxmenu=1;
3311      }      }
3312    
3313      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3322  int main(int argc, const char ** argv) {
3322        #elif __s390x__        #elif __s390x__
3323          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3324        #else        #else
3325   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3326        cfi = &grub2ConfigType;
3327     else
3328        cfi = &grubConfigType;
3329        #endif        #endif
3330      }      }
3331    
3332      if (!grubConfig)      if (!grubConfig) {
3333   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3334        grubConfig = cfi->findConfig(cfi);
3335     if (!grubConfig)
3336        grubConfig = cfi->defaultConfig;
3337        }
3338    
3339      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3340    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3341    defaultKernel)) {    defaultKernel || displayDefaultIndex)) {
3342   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3343    "specified option"));    "specified option"));
3344   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3354  int main(int argc, const char ** argv) {
3354      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3355   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3356   return 1;   return 1;
3357      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3358    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3359    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3360   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3361   return 1;   return 1;
3362      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3381  int main(int argc, const char ** argv) {
3381   defaultKernel = NULL;   defaultKernel = NULL;
3382      }      }
3383    
3384      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3385   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3386   "is used\n"));   "is used\n"));
3387   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3389  int main(int argc, const char ** argv) {
3389    
3390      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3391   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3392          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex) {
3393   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3394   return 1;   return 1;
3395      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3409  int main(int argc, const char ** argv) {
3409   bootPrefix = "";   bootPrefix = "";
3410      }      }
3411    
3412        if (!cfi->mbAllowExtraInitRds &&
3413     extraInitrdCount > 0) {
3414     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3415     return 1;
3416        }
3417    
3418      if (bootloaderProbe) {      if (bootloaderProbe) {
3419   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3420   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3421    
3422   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3423      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3424        gconfig = readConfig(grub2config, &grub2ConfigType);
3425        if (!gconfig)
3426     gr2c = 1;
3427        else
3428     gr2c = checkForGrub2(gconfig);
3429     }
3430    
3431     const char *grubconfig = grubFindConfig(&grubConfigType);
3432     if (!access(grubconfig, F_OK)) {
3433        gconfig = readConfig(grubconfig, &grubConfigType);
3434      if (!gconfig)      if (!gconfig)
3435   grc = 1;   grc = 1;
3436      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3445  int main(int argc, const char ** argv) {
3445   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3446   }   }
3447    
3448   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3449        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3450        if (!lconfig)
3451     erc = 1;
3452        else
3453     erc = checkForExtLinux(lconfig);
3454     }
3455    
3456     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3457    
3458   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3459     if (gr2c == 2) printf("grub2\n");
3460   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3461     if (erc == 2) printf("extlinux\n");
3462    
3463   return 0;   return 0;
3464      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3476  int main(int argc, const char ** argv) {
3476   if (!entry) return 0;   if (!entry) return 0;
3477   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3478    
3479   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3480   if (!line) return 0;   if (!line) return 0;
3481    
3482          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3484  int main(int argc, const char ** argv) {
3484                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3485    
3486   return 0;   return 0;
3487    
3488        } else if (displayDefaultIndex) {
3489            if (config->defaultImage == -1) return 0;
3490            printf("%i\n", config->defaultImage);
3491    
3492      } else if (kernelInfo)      } else if (kernelInfo)
3493   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3494    
# Line 2585  int main(int argc, const char ** argv) { Line 3504  int main(int argc, const char ** argv) {
3504      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3505      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3506                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3507        if (updateKernelPath && newKernelInitrd) {
3508                if (updateInitrd(config, updateKernelPath, bootPrefix,
3509                                 newKernelInitrd)) return 1;
3510        }
3511      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3512                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3513                         extraInitrds, extraInitrdCount,
3514                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3515            
3516    
# Line 2597  int main(int argc, const char ** argv) { Line 3521  int main(int argc, const char ** argv) {
3521      }      }
3522    
3523      if (!outputFile)      if (!outputFile)
3524   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3525    
3526      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3527  }  }

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