Magellan Linux

Diff of /trunk/grubby/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 1736 by niro, Sat Feb 18 01:02:17 2012 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39    #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43  #include "mount_by_label.h"  #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49    int debug = 0; /* Currently just for template debugging */
50    
51  #define _(A) (A)  #define _(A) (A)
52    
53    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
54  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
55    
56    #define NOOP_OPCODE 0x90
57    #define JMP_SHORT_OPCODE 0xeb
58    
59  /* comments get lumped in with indention */  /* comments get lumped in with indention */
60  struct lineElement {  struct lineElement {
61      char * item;      char * item;
62      char * indent;      char * indent;
63  };  };
64    
65  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
66         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
67         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
68        LT_KERNEL       = 1 << 2,
69        LT_INITRD       = 1 << 3,
70        LT_HYPER        = 1 << 4,
71        LT_DEFAULT      = 1 << 5,
72        LT_MBMODULE     = 1 << 6,
73        LT_ROOT         = 1 << 7,
74        LT_FALLBACK     = 1 << 8,
75        LT_KERNELARGS   = 1 << 9,
76        LT_BOOT         = 1 << 10,
77        LT_BOOTROOT     = 1 << 11,
78        LT_LBA          = 1 << 12,
79        LT_OTHER        = 1 << 13,
80        LT_GENERIC      = 1 << 14,
81        LT_ECHO    = 1 << 16,
82        LT_MENUENTRY    = 1 << 17,
83        LT_ENTRY_END    = 1 << 18,
84        LT_SET_VARIABLE = 1 << 19,
85        LT_UNKNOWN      = 1 << 20,
86    };
87    
88  struct singleLine {  struct singleLine {
89      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 104  struct singleEntry {
104    
105  #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 */
106    
107  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
108  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
109  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
110  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
111  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
112    #define NEED_MB      (1 << 4)
113    #define NEED_END     (1 << 5)
114    
115  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
116  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 74  struct keywordTypes { Line 119  struct keywordTypes {
119      char * key;      char * key;
120      enum lineType_e type;      enum lineType_e type;
121      char nextChar;      char nextChar;
122  } ;      char separatorChar;
123    };
124    
125    struct configFileInfo;
126    
127    typedef const char *(*findConfigFunc)(struct configFileInfo *);
128    typedef const int (*writeLineFunc)(struct configFileInfo *,
129     struct singleLine *line);
130    
131  struct configFileInfo {  struct configFileInfo {
132      char * defaultConfig;      char * defaultConfig;
133        findConfigFunc findConfig;
134        writeLineFunc writeLine;
135      struct keywordTypes * keywords;      struct keywordTypes * keywords;
136      int defaultIsIndex;      int defaultIsIndex;
137        int defaultIsVariable;
138      int defaultSupportSaved;      int defaultSupportSaved;
139      enum lineType_e entrySeparator;      enum lineType_e entryStart;
140        enum lineType_e entryEnd;
141      int needsBootPrefix;      int needsBootPrefix;
142      int argsInQuotes;      int argsInQuotes;
143      int maxTitleLength;      int maxTitleLength;
144      int titleBracketed;      int titleBracketed;
145        int titlePosition;
146        int mbHyperFirst;
147        int mbInitRdIsModule;
148        int mbConcatArgs;
149        int mbAllowExtraInitRds;
150  };  };
151    
152  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 155  struct keywordTypes grubKeywords[] = {
155      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
156      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
157      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
158      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
159      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
160        { "kernel",     LT_HYPER,       ' ' },
161      { NULL,    0, 0 },      { NULL,    0, 0 },
162  };  };
163    
164    const char *grubFindConfig(struct configFileInfo *cfi) {
165        static const char *configFiles[] = {
166     "/etc/grub.conf",
167     "/boot/grub/grub.conf",
168     "/boot/grub/menu.lst",
169     NULL
170        };
171        static int i = -1;
172    
173        if (i == -1) {
174     for (i = 0; configFiles[i] != NULL; i++) {
175        dbgPrintf("Checking \"%s\": ", configFiles[i]);
176        if (!access(configFiles[i], R_OK)) {
177     dbgPrintf("found\n");
178     return configFiles[i];
179        }
180        dbgPrintf("not found\n");
181     }
182        }
183        return configFiles[i];
184    }
185    
186  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
187      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
188      grubKeywords,    /* keywords */      .keywords = grubKeywords,
189      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
190      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
191      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
192      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
193      0,    /* argsInQuotes */      .mbHyperFirst = 1,
194      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
195      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
196    };
197    
198    struct keywordTypes grub2Keywords[] = {
199        { "menuentry",  LT_MENUENTRY,   ' ' },
200        { "}",          LT_ENTRY_END,   ' ' },
201        { "echo",       LT_ECHO,        ' ' },
202        { "set",        LT_SET_VARIABLE,' ', '=' },
203        { "root",       LT_BOOTROOT,    ' ' },
204        { "default",    LT_DEFAULT,     ' ' },
205        { "fallback",   LT_FALLBACK,    ' ' },
206        { "linux",      LT_KERNEL,      ' ' },
207        { "initrd",     LT_INITRD,      ' ', ' ' },
208        { "module",     LT_MBMODULE,    ' ' },
209        { "kernel",     LT_HYPER,       ' ' },
210        { NULL, 0, 0 },
211    };
212    
213    const char *grub2FindConfig(struct configFileInfo *cfi) {
214        static const char *configFiles[] = {
215     "/boot/grub/grub-efi.cfg",
216     "/boot/grub/grub.cfg",
217     NULL
218        };
219        static int i = -1;
220        static const char *grub_cfg = "/boot/grub/grub.cfg";
221    
222        if (i == -1) {
223     for (i = 0; configFiles[i] != NULL; i++) {
224        dbgPrintf("Checking \"%s\": ", configFiles[i]);
225        if (!access(configFiles[i], R_OK)) {
226     dbgPrintf("found\n");
227     return configFiles[i];
228        }
229     }
230        }
231    
232        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
233         * that isn't in grub1, and if it exists, return the config file path
234         * that they use. */
235        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
236     dbgPrintf("found\n");
237     return grub_cfg;
238        }
239    
240        dbgPrintf("not found\n");
241        return configFiles[i];
242    }
243    
244    struct configFileInfo grub2ConfigType = {
245        .findConfig = grub2FindConfig,
246        .keywords = grub2Keywords,
247        .defaultIsIndex = 1,
248        .defaultSupportSaved = 0,
249        .defaultIsVariable = 1,
250        .entryStart = LT_MENUENTRY,
251        .entryEnd = LT_ENTRY_END,
252        .titlePosition = 1,
253        .needsBootPrefix = 1,
254        .mbHyperFirst = 1,
255        .mbInitRdIsModule = 1,
256        .mbAllowExtraInitRds = 1,
257  };  };
258    
259  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 287  struct keywordTypes yabootKeywords[] = {
287      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
288      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
289      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
290      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
291      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
292      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
293      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 307  struct keywordTypes liloKeywords[] = {
307      { NULL,    0, 0 },      { NULL,    0, 0 },
308  };  };
309    
310    struct keywordTypes eliloKeywords[] = {
311        { "label",    LT_TITLE,    '=' },
312        { "root",    LT_ROOT,    '=' },
313        { "default",    LT_DEFAULT,    '=' },
314        { "image",    LT_KERNEL,    '=' },
315        { "initrd",    LT_INITRD,    '=' },
316        { "append",    LT_KERNELARGS,  '=' },
317        { "vmm",    LT_HYPER,       '=' },
318        { NULL,    0, 0 },
319    };
320    
321  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
322      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
323      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 339  struct keywordTypes ziplKeywords[] = {
339      { NULL,         0, 0 },      { NULL,         0, 0 },
340  };  };
341    
342    struct keywordTypes extlinuxKeywords[] = {
343        { "label",    LT_TITLE,    ' ' },
344        { "root",    LT_ROOT,    ' ' },
345        { "default",    LT_DEFAULT,    ' ' },
346        { "kernel",    LT_KERNEL,    ' ' },
347        { "initrd",    LT_INITRD,      ' ', ',' },
348        { "append",    LT_KERNELARGS,  ' ' },
349        { "prompt",     LT_UNKNOWN,     ' ' },
350        { NULL,    0, 0 },
351    };
352    int useextlinuxmenu;
353  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
354      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
355      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
356      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
357      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
358      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
359      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
360  };  };
361    
362  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
363      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
364      liloKeywords,    /* keywords */      .keywords = liloKeywords,
365      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
366      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
367      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
368  };  };
369    
370  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
371      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
372      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
373      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
374      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
375      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
376      1,    /* needsBootPrefix */      .maxTitleLength = 15,
377      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
378  };  };
379    
380  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
381      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
382      siloKeywords,    /* keywords */      .keywords = siloKeywords,
383      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
384      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
385      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
386      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
387  };  };
388    
389  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
390      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
391      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
392      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
393      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
394      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
395      0,    /* needsBootPrefix */  };
396      1,    /* argsInQuotes */  
397      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
398      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
399        .keywords = extlinuxKeywords,
400        .entryStart = LT_TITLE,
401        .needsBootPrefix = 1,
402        .maxTitleLength = 255,
403        .mbAllowExtraInitRds = 1,
404  };  };
405    
406  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 415  struct grubConfig {
415      struct configFileInfo * cfi;      struct configFileInfo * cfi;
416  };  };
417    
418    blkid_cache blkid;
419    
420  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
421  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
422       const char * path, const char * prefix,       const char * path, const char * prefix,
423       int * index);       int * index);
 static char * strndup(char * from, int len);  
424  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
425  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
426    struct singleLine * lineDup(struct singleLine * line);
427  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
428  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
429       struct configFileInfo * cfi);       struct configFileInfo * cfi);
430  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
431         struct configFileInfo * cfi);         struct configFileInfo * cfi);
432  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
433    static void requote(struct singleLine *line, struct configFileInfo * cfi);
434  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
435      char * to;    const char * item, int insertHere,
436      struct configFileInfo * cfi);
437      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
438      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
439      to[len] = '\0';        struct configFileInfo * cfi);
440    static enum lineType_e getTypeByKeyword(char * keyword,
441      return to;   struct configFileInfo * cfi);
442  }  static struct singleLine * getLineByType(enum lineType_e type,
443     struct singleLine * line);
444    static int checkForExtLinux(struct grubConfig * config);
445    struct singleLine * addLineTmpl(struct singleEntry * entry,
446                                    struct singleLine * tmplLine,
447                                    struct singleLine * prevLine,
448                                    const char * val,
449     struct configFileInfo * cfi);
450    struct singleLine *  addLine(struct singleEntry * entry,
451                                 struct configFileInfo * cfi,
452                                 enum lineType_e type, char * defaultIndent,
453                                 const char * val);
454    
455  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
456  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 485  static char * sdupprintf(const char *for
485      return buf;      return buf;
486  }  }
487    
488    static struct keywordTypes * getKeywordByType(enum lineType_e type,
489          struct configFileInfo * cfi) {
490        struct keywordTypes * kw;
491        for (kw = cfi->keywords; kw->key; kw++) {
492     if (kw->type == type)
493        return kw;
494        }
495        return NULL;
496    }
497    
498    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
499        struct keywordTypes *kt = getKeywordByType(type, cfi);
500        if (kt)
501     return kt->key;
502        return "unknown";
503    }
504    
505    static char * getpathbyspec(char *device) {
506        if (!blkid)
507            blkid_get_cache(&blkid, NULL);
508    
509        return blkid_get_devname(blkid, device, NULL);
510    }
511    
512    static char * getuuidbydev(char *device) {
513        if (!blkid)
514     blkid_get_cache(&blkid, NULL);
515    
516        return blkid_get_tag_value(blkid, "UUID", device);
517    }
518    
519    static enum lineType_e getTypeByKeyword(char * keyword,
520     struct configFileInfo * cfi) {
521        struct keywordTypes * kw;
522        for (kw = cfi->keywords; kw->key; kw++) {
523     if (!strcmp(keyword, kw->key))
524        return kw->type;
525        }
526        return LT_UNKNOWN;
527    }
528    
529    static struct singleLine * getLineByType(enum lineType_e type,
530     struct singleLine * line) {
531        dbgPrintf("getLineByType(%d): ", type);
532        for (; line; line = line->next) {
533     dbgPrintf("%d:%s ", line->type,
534      line->numElements ? line->elements[0].item : "(empty)");
535     if (line->type & type) break;
536        }
537        dbgPrintf(line ? "\n" : " (failed)\n");
538        return line;
539    }
540    
541  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
542      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
543          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
544          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
545              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 551  static int isBracketedTitle(struct singl
551      return 0;      return 0;
552  }  }
553    
554  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
555                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
556      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
557   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;  
558  }  }
559    
560  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 605  static void lineInit(struct singleLine *
605      line->next = NULL;      line->next = NULL;
606  }  }
607    
608    struct singleLine * lineDup(struct singleLine * line) {
609        int i;
610        struct singleLine * newLine = malloc(sizeof(*newLine));
611    
612        newLine->indent = strdup(line->indent);
613        newLine->next = NULL;
614        newLine->type = line->type;
615        newLine->numElements = line->numElements;
616        newLine->elements = malloc(sizeof(*newLine->elements) *
617           newLine->numElements);
618    
619        for (i = 0; i < newLine->numElements; i++) {
620     newLine->elements[i].indent = strdup(line->elements[i].indent);
621     newLine->elements[i].item = strdup(line->elements[i].item);
622        }
623    
624        return newLine;
625    }
626    
627  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
628      int i;      int i;
629    
# Line 414  static int lineWrite(FILE * out, struct Line 649  static int lineWrite(FILE * out, struct
649      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
650    
651   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
652   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
653        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
654      }      }
655    
656      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 669  static int getNextLine(char ** bufPtr, s
669      char * chptr;      char * chptr;
670      int elementsAlloced = 0;      int elementsAlloced = 0;
671      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
672      int first = 1;      int first = 1;
     int i;  
673    
674      lineFree(line);      lineFree(line);
675    
# Line 489  static int getNextLine(char ** bufPtr, s Line 723  static int getNextLine(char ** bufPtr, s
723      if (!line->numElements)      if (!line->numElements)
724   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
725      else {      else {
726   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
727      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;  
               
728              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
729               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
730              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 760  static int getNextLine(char ** bufPtr, s
760   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
761   line->numElements = 0;   line->numElements = 0;
762      }      }
763     } else {
764     struct keywordTypes *kw;
765    
766     kw = getKeywordByType(line->type, cfi);
767    
768     /* space isn't the only separator, we need to split
769     * elements up more
770     */
771     if (!isspace(kw->separatorChar)) {
772        int i;
773        char indent[2] = "";
774        indent[0] = kw->separatorChar;
775        for (i = 1; i < line->numElements; i++) {
776     char *p;
777     int j;
778     int numNewElements;
779    
780     numNewElements = 0;
781     p = line->elements[i].item;
782     while (*p != '\0') {
783     if (*p == kw->separatorChar)
784     numNewElements++;
785     p++;
786     }
787     if (line->numElements + numNewElements >= elementsAlloced) {
788     elementsAlloced += numNewElements + 5;
789     line->elements = realloc(line->elements,
790        sizeof(*line->elements) * elementsAlloced);
791     }
792    
793     for (j = line->numElements; j > i; j--) {
794     line->elements[j + numNewElements] = line->elements[j];
795     }
796     line->numElements += numNewElements;
797    
798     p = line->elements[i].item;
799     while (*p != '\0') {
800    
801     while (*p != kw->separatorChar && *p != '\0') p++;
802     if (*p == '\0') {
803     break;
804     }
805    
806     free(line->elements[i].indent);
807     line->elements[i].indent = strdup(indent);
808     *p++ = '\0';
809     i++;
810     line->elements[i].item = strdup(p);
811     line->elements[i].indent = strdup("");
812     p = line->elements[i].item;
813     }
814        }
815     }
816   }   }
817      }      }
818    
# Line 595  static struct grubConfig * readConfig(co Line 876  static struct grubConfig * readConfig(co
876      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
877   }   }
878    
879   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
880      sawEntry = 1;      sawEntry = 1;
881      if (!entry) {      if (!entry) {
882   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 892  static struct grubConfig * readConfig(co
892      entry->next = NULL;      entry->next = NULL;
893   }   }
894    
895   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
896        int i;
897        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
898        dbgPrintf("%s", line->indent);
899        for (i = 0; i < line->numElements; i++)
900     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
901        dbgPrintf("\n");
902        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
903        if (kwType && line->numElements == 3 &&
904        !strcmp(line->elements[1].item, kwType->key)) {
905     dbgPrintf("Line sets default config\n");
906     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
907     defaultLine = line;
908        }
909     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
910      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
911      defaultLine = line;      defaultLine = line;
912    
913            } else if (line->type == LT_KERNEL) {
914        /* if by some freak chance this is multiboot and the "module"
915         * lines came earlier in the template, make sure to use LT_HYPER
916         * instead of LT_KERNEL now
917         */
918        if (entry->multiboot)
919     line->type = LT_HYPER;
920    
921          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
922        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
923         * instead, now that we know this is a multiboot entry.
924         * This only applies to grub, but that's the only place we
925         * should find LT_MBMODULE lines anyway.
926         */
927        struct singleLine * l;
928        for (l = entry->lines; l; l = l->next) {
929     if (l->type == LT_HYPER)
930        break;
931     else if (l->type == LT_KERNEL) {
932        l->type = LT_HYPER;
933        break;
934     }
935        }
936              entry->multiboot = 1;              entry->multiboot = 1;
937    
938     } else if (line->type == LT_HYPER) {
939        entry->multiboot = 1;
940    
941   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
942      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
943      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
944    
945   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
946      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
947      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 966  static struct grubConfig * readConfig(co
966      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
967      line->elements[1].item = buf;      line->elements[1].item = buf;
968      line->numElements = 2;      line->numElements = 2;
969    
970   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
971      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
972         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 976  static struct grubConfig * readConfig(co
976   int last, len;   int last, len;
977    
978   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
979      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
980     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
981    
982   last = line->numElements - 1;   last = line->numElements - 1;
983   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
984   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
985      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
986      }      }
   
987   }   }
988    
989   /* 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 1003  static struct grubConfig * readConfig(co
1003   movedLine = 1;   movedLine = 1;
1004   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1005   }   }
1006    
1007   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1008     which was moved, drop it. */     which was moved, drop it. */
1009   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 1019  static struct grubConfig * readConfig(co
1019   entry->lines = line;   entry->lines = line;
1020      else      else
1021   last->next = line;   last->next = line;
1022        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1023    
1024        /* we could have seen this outside of an entry... if so, we
1025         * ignore it like any other line we don't grok */
1026        if (line->type == LT_ENTRY_END && sawEntry)
1027     sawEntry = 0;
1028   } else {   } else {
1029      if (!cfg->theLines)      if (!cfg->theLines)
1030   cfg->theLines = line;   cfg->theLines = line;
1031      else {      else
1032   last->next = line;   last->next = line;
1033      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1034   }   }
1035    
1036   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1038  static struct grubConfig * readConfig(co
1038    
1039      free(incoming);      free(incoming);
1040    
1041        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1042      if (defaultLine) {      if (defaultLine) {
1043   if (cfi->defaultSupportSaved &&   if (cfi->defaultIsVariable) {
1044        char *value = defaultLine->elements[2].item;
1045        while (*value && (*value == '"' || *value == '\'' ||
1046        *value == ' ' || *value == '\t'))
1047     value++;
1048        cfg->defaultImage = strtol(value, &end, 10);
1049        while (*end && (*end == '"' || *end == '\'' ||
1050        *end == ' ' || *end == '\t'))
1051     end++;
1052        if (*end) cfg->defaultImage = -1;
1053     } else if (cfi->defaultSupportSaved &&
1054   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1055      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1056   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1071  static struct grubConfig * readConfig(co
1071                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1072                  }                  }
1073   i++;   i++;
1074     entry = NULL;
1075      }      }
1076    
1077      if (entry) cfg->defaultImage = i;      if (entry){
1078            cfg->defaultImage = i;
1079        }else{
1080            cfg->defaultImage = -1;
1081        }
1082   }   }
1083        } else {
1084            cfg->defaultImage = 0;
1085      }      }
1086    
1087      return cfg;      return cfg;
# Line 751  static void writeDefault(FILE * out, cha Line 1099  static void writeDefault(FILE * out, cha
1099   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1100      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1101   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1102      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1103      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1104     cfg->defaultImage);
1105        } else {
1106     fprintf(out, "%sdefault%s%d\n", indent, separator,
1107     cfg->defaultImage);
1108        }
1109   } else {   } else {
1110      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1111    
# Line 769  static void writeDefault(FILE * out, cha Line 1122  static void writeDefault(FILE * out, cha
1122    
1123      if (!entry) return;      if (!entry) return;
1124    
1125      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1126    
1127      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1128   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1156  static int writeConfig(struct grubConfig
1156      int rc;      int rc;
1157    
1158      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1159         directory to / */         directory to the dir of the symlink */
1160      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1161      do {      do {
1162   buf = alloca(len + 1);   buf = alloca(len + 1);
1163   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1164   if (rc == len) len += 256;   if (rc == len) len += 256;
1165      } while (rc == len);      } while (rc == len);
1166            
# Line 843  static int writeConfig(struct grubConfig Line 1195  static int writeConfig(struct grubConfig
1195      }      }
1196    
1197      line = cfg->theLines;      line = cfg->theLines;
1198        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1199      while (line) {      while (line) {
1200   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1201     line->numElements == 3 &&
1202     !strcmp(line->elements[1].item, defaultKw->key)) {
1203        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1204        needs &= ~MAIN_DEFAULT;
1205     } else if (line->type == LT_DEFAULT) {
1206      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1207      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1208   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1270  static int numEntries(struct grubConfig
1270      return i;      return i;
1271  }  }
1272    
1273    static char *findDiskForRoot()
1274    {
1275        int fd;
1276        char buf[65536];
1277        char *devname;
1278        char *chptr;
1279        int rc;
1280    
1281        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1282            fprintf(stderr, "grubby: failed to open %s: %s\n",
1283                    _PATH_MOUNTED, strerror(errno));
1284            return NULL;
1285        }
1286    
1287        rc = read(fd, buf, sizeof(buf) - 1);
1288        if (rc <= 0) {
1289            fprintf(stderr, "grubby: failed to read %s: %s\n",
1290                    _PATH_MOUNTED, strerror(errno));
1291            close(fd);
1292            return NULL;
1293        }
1294        close(fd);
1295        buf[rc] = '\0';
1296        chptr = buf;
1297    
1298        while (chptr && chptr != buf+rc) {
1299            devname = chptr;
1300    
1301            /*
1302             * The first column of a mtab entry is the device, but if the entry is a
1303             * special device it won't start with /, so move on to the next line.
1304             */
1305            if (*devname != '/') {
1306                chptr = strchr(chptr, '\n');
1307                if (chptr)
1308                    chptr++;
1309                continue;
1310            }
1311    
1312            /* Seek to the next space */
1313            chptr = strchr(chptr, ' ');
1314            if (!chptr) {
1315                fprintf(stderr, "grubby: error parsing %s: %s\n",
1316                        _PATH_MOUNTED, strerror(errno));
1317                return NULL;
1318            }
1319    
1320            /*
1321             * The second column of a mtab entry is the mount point, we are looking
1322             * for '/' obviously.
1323             */
1324            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1325                /*
1326                 * Move back 2, which is the first space after the device name, set
1327                 * it to \0 so strdup will just get the devicename.
1328                 */
1329                chptr -= 2;
1330                *chptr = '\0';
1331                return strdup(devname);
1332            }
1333    
1334            /* Next line */
1335            chptr = strchr(chptr, '\n');
1336            if (chptr)
1337                chptr++;
1338        }
1339    
1340        return NULL;
1341    }
1342    
1343    void printEntry(struct singleEntry * entry) {
1344        int i;
1345        struct singleLine * line;
1346    
1347        for (line = entry->lines; line; line = line->next) {
1348     fprintf(stderr, "DBG: %s", line->indent);
1349     for (i = 0; i < line->numElements; i++) {
1350     fprintf(stderr, "%s%s",
1351        line->elements[i].item, line->elements[i].indent);
1352     }
1353     fprintf(stderr, "\n");
1354        }
1355    }
1356    
1357    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1358    {
1359        va_list argp;
1360    
1361        if (!debug)
1362     return;
1363    
1364        va_start(argp, fmt);
1365        fprintf(stderr, "DBG: Image entry failed: ");
1366        vfprintf(stderr, fmt, argp);
1367        printEntry(entry);
1368        va_end(argp);
1369    }
1370    
1371  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1372    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1373      struct singleLine * line;      struct singleLine * line;
1374      char * fullName;      char * fullName;
1375      int i;      int i;
     struct stat sb, sb2;  
1376      char * dev;      char * dev;
     char * end;  
1377      char * rootspec;      char * rootspec;
1378        char * rootdev;
1379    
1380      line = entry->lines;      if (skipRemoved && entry->skip) {
1381      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1382         return 0;
1383      if (!line) return 0;      }
1384      if (skipRemoved && entry->skip) return 0;  
1385      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1386        if (!line) {
1387     notSuitablePrintf(entry, "no line found\n");
1388     return 0;
1389        }
1390        if (line->numElements < 2) {
1391     notSuitablePrintf(entry, "line has only %d elements\n",
1392        line->numElements);
1393     return 0;
1394        }
1395    
1396      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1397    
# Line 935  int suitableImage(struct singleEntry * e Line 1399  int suitableImage(struct singleEntry * e
1399        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1400      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1401      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1402              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
1403                                        strlen(rootspec) : 0));      if (access(fullName, R_OK)) {
1404      if (access(fullName, R_OK)) return 0;   notSuitablePrintf(entry, "access to %s failed\n", fullName);
1405     return 0;
1406        }
1407      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1408   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1409      if (i < line->numElements) {      if (i < line->numElements) {
1410   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1411      } else {      } else {
1412   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1413   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1414    
1415   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1416      dev = line->elements[1].item;      dev = line->elements[1].item;
1417   } else {   } else {
1418              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1419      /* 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.
1420      line = entry->lines;       */
1421        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1422    
1423              /* failed to find one */              /* failed to find one */
1424              if (!line) return 0;              if (!line) {
1425     notSuitablePrintf(entry, "no line found\n");
1426     return 0;
1427                }
1428    
1429      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1430          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1431      if (i < line->numElements)      if (i < line->numElements)
1432          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1433      else {      else {
1434     notSuitablePrintf(entry, "no root= entry found\n");
1435   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1436          return 0;          return 0;
1437              }              }
1438   }   }
1439      }      }
1440    
1441      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1442   dev += 6;      if (!getpathbyspec(dev)) {
1443            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1444   /* check which device has this label */          return 0;
1445   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1446   if (!dev) return 0;   dev = getpathbyspec(dev);
1447    
1448        rootdev = findDiskForRoot();
1449        if (!rootdev) {
1450            notSuitablePrintf(entry, "can't find root device\n");
1451     return 0;
1452      }      }
1453    
1454      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1455   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1456      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1457      } else {          free(rootdev);
1458   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1459   if (*end) return 0;      }
1460    
1461        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1462            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1463     getuuidbydev(rootdev), getuuidbydev(dev));
1464     free(rootdev);
1465            return 0;
1466      }      }
     stat("/", &sb2);  
1467    
1468      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1469    
1470      return 1;      return 1;
1471  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1509  struct singleEntry * findEntryByPath(str
1509   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1510   if (!entry) return NULL;   if (!entry) return NULL;
1511    
1512   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1513   if (!line) return NULL;   if (!line) return NULL;
1514    
1515   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1551  struct singleEntry * findEntryByPath(str
1551      kernel += 6;      kernel += 6;
1552   }   }
1553    
1554   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1555      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1556    
1557        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1558    
1559      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1560                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1561          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1562                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1563                              kernel + strlen(prefix)))       checkType, line);
1564                      break;   if (!line) break;  /* not found in this entry */
1565              }  
1566                 if (line && line->numElements >= 2) {
1567              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1568              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1569                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1570                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1571                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1572                      if (!strcmp(line->elements[1].item  +   }
1573                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1574    
1575      i++;      /* make sure this entry has a kernel identifier; this skips
1576         * non-Linux boot entries (could find netbsd etc, though, which is
1577         * unfortunate)
1578         */
1579        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1580     break; /* found 'im! */
1581   }   }
1582    
1583   if (index) *index = i;   if (index) *index = i;
1584      }      }
1585    
     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);  
     }  
   
1586      return entry;      return entry;
1587  }  }
1588    
# Line 1286  void displayEntry(struct singleEntry * e Line 1747  void displayEntry(struct singleEntry * e
1747      char * root = NULL;      char * root = NULL;
1748      int i;      int i;
1749    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1750      printf("index=%d\n", index);      printf("index=%d\n", index);
1751    
1752        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1753        if (!line) {
1754            printf("non linux entry\n");
1755            return;
1756        }
1757    
1758      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1759    
1760      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1772  void displayEntry(struct singleEntry * e
1772   }   }
1773   printf("\"\n");   printf("\"\n");
1774      } else {      } else {
1775   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1776   if (line) {   if (line) {
1777      char * s;      char * s;
1778    
# Line 1334  void displayEntry(struct singleEntry * e Line 1796  void displayEntry(struct singleEntry * e
1796      }      }
1797    
1798      if (!root) {      if (!root) {
1799   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1800   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1801      root=line->elements[1].item;      root=line->elements[1].item;
1802      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1811  void displayEntry(struct singleEntry * e
1811   printf("root=%s\n", s);   printf("root=%s\n", s);
1812      }      }
1813    
1814      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1815    
1816      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1817   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1828  int parseSysconfigGrub(int * lbaPtr, cha
1828      char * start;      char * start;
1829      char * param;      char * param;
1830    
1831      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1832      if (!in) return 1;      if (!in) return 1;
1833    
1834      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1890  int displayInfo(struct grubConfig * conf
1890   return 1;   return 1;
1891      }      }
1892    
1893      /* 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
1894         be a better way */         be a better way */
1895      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1896   dumpSysconfigGrub();   dumpSysconfigGrub();
1897      } else {      } else {
1898   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1899   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1900      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1901   }   }
1902    
1903   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1904   if (line) printf("lba\n");   if (line) printf("lba\n");
1905      }      }
1906    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1915  int displayInfo(struct grubConfig * conf
1915      return 0;      return 0;
1916  }  }
1917    
1918    struct singleLine * addLineTmpl(struct singleEntry * entry,
1919     struct singleLine * tmplLine,
1920     struct singleLine * prevLine,
1921     const char * val,
1922     struct configFileInfo * cfi)
1923    {
1924        struct singleLine * newLine = lineDup(tmplLine);
1925    
1926        if (val) {
1927     /* override the inherited value with our own.
1928     * This is a little weak because it only applies to elements[1]
1929     */
1930     if (newLine->numElements > 1)
1931        removeElement(newLine, 1);
1932     insertElement(newLine, val, 1, cfi);
1933    
1934     /* but try to keep the rootspec from the template... sigh */
1935     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1936        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1937        if (rootspec != NULL) {
1938     free(newLine->elements[1].item);
1939     newLine->elements[1].item =
1940        sdupprintf("%s%s", rootspec, val);
1941        }
1942     }
1943        }
1944    
1945        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1946          newLine->elements[0].item : "");
1947    
1948        if (!entry->lines) {
1949     /* first one on the list */
1950     entry->lines = newLine;
1951        } else if (prevLine) {
1952     /* add after prevLine */
1953     newLine->next = prevLine->next;
1954     prevLine->next = newLine;
1955        }
1956    
1957        return newLine;
1958    }
1959    
1960  /* val may be NULL */  /* val may be NULL */
1961  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1962       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1963       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1964       char * val) {       const char * val) {
1965      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1966      int i;      struct keywordTypes * kw;
1967        struct singleLine tmpl;
1968    
1969      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1970   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1971      if (type != LT_TITLE || !cfi->titleBracketed)       */
1972          if (!cfi->keywords[i].key) abort();  
1973        if (type == LT_TITLE && cfi->titleBracketed) {
1974     /* we're doing a bracketed title (zipl) */
1975     tmpl.type = type;
1976     tmpl.numElements = 1;
1977     tmpl.elements = alloca(sizeof(*tmpl.elements));
1978     tmpl.elements[0].item = alloca(strlen(val)+3);
1979     sprintf(tmpl.elements[0].item, "[%s]", val);
1980     tmpl.elements[0].indent = "";
1981     val = NULL;
1982        } else if (type == LT_MENUENTRY) {
1983     char *lineend = "--class gnu-linux --class gnu --class os {";
1984     if (!val) {
1985        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
1986        abort();
1987     }
1988     kw = getKeywordByType(type, cfi);
1989     if (!kw) {
1990        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1991        abort();
1992     }
1993     tmpl.indent = "";
1994     tmpl.type = type;
1995     tmpl.numElements = 3;
1996     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1997     tmpl.elements[0].item = kw->key;
1998     tmpl.elements[0].indent = alloca(2);
1999     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2000     tmpl.elements[1].item = (char *)val;
2001     tmpl.elements[1].indent = alloca(2);
2002     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2003     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2004     strcpy(tmpl.elements[2].item, lineend);
2005     tmpl.elements[2].indent = "";
2006        } else {
2007     kw = getKeywordByType(type, cfi);
2008     if (!kw) {
2009        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2010        abort();
2011     }
2012     tmpl.type = type;
2013     tmpl.numElements = val ? 2 : 1;
2014     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2015     tmpl.elements[0].item = kw->key;
2016     tmpl.elements[0].indent = alloca(2);
2017     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2018     if (val) {
2019        tmpl.elements[1].item = (char *)val;
2020        tmpl.elements[1].indent = "";
2021     }
2022        }
2023    
2024      /* 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
2025         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2026         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
2027         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2028         differently from the rest) */         differently from the rest) */
2029      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2030   line = entry->lines;   if (line->numElements) prev = line;
2031   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2032   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;  
2033      }      }
2034    
2035      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2036          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2037          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2038          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2039          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2040          line->elements[0].indent = malloc(2);   else
2041          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2042          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2043             if (menuEntry)
2044          if (val) {      tmpl.indent = "\t";
2045              line->elements[1].item = val;   else if (prev == entry->lines)
2046              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2047          }   else
2048      } 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("");  
2049      }      }
2050    
2051      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2052  }  }
2053    
2054  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2073  void removeLine(struct singleEntry * ent
2073      free(line);      free(line);
2074  }  }
2075    
2076    static int isquote(char q)
2077    {
2078        if (q == '\'' || q == '\"')
2079     return 1;
2080        return 0;
2081    }
2082    
2083    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2084    {
2085        struct singleLine newLine = {
2086     .indent = tmplLine->indent,
2087     .type = tmplLine->type,
2088     .next = tmplLine->next,
2089        };
2090        int firstQuotedItem = -1;
2091        int quoteLen = 0;
2092        int j;
2093        int element = 0;
2094        char *c;
2095    
2096        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2097        strcpy(c, tmplLine->elements[0].item);
2098        insertElement(&newLine, c, element++, cfi);
2099        free(c);
2100        c = NULL;
2101    
2102        for (j = 1; j < tmplLine->numElements; j++) {
2103     if (firstQuotedItem == -1) {
2104        quoteLen += strlen(tmplLine->elements[j].item);
2105        
2106        if (isquote(tmplLine->elements[j].item[0])) {
2107     firstQuotedItem = j;
2108            quoteLen += strlen(tmplLine->elements[j].indent);
2109        } else {
2110     c = malloc(quoteLen + 1);
2111     strcpy(c, tmplLine->elements[j].item);
2112     insertElement(&newLine, c, element++, cfi);
2113     free(c);
2114     quoteLen = 0;
2115        }
2116     } else {
2117        int itemlen = strlen(tmplLine->elements[j].item);
2118        quoteLen += itemlen;
2119        quoteLen += strlen(tmplLine->elements[j].indent);
2120        
2121        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2122     c = malloc(quoteLen + 1);
2123     c[0] = '\0';
2124     for (int i = firstQuotedItem; i < j+1; i++) {
2125        strcat(c, tmplLine->elements[i].item);
2126        strcat(c, tmplLine->elements[i].indent);
2127     }
2128     insertElement(&newLine, c, element++, cfi);
2129     free(c);
2130    
2131     firstQuotedItem = -1;
2132     quoteLen = 0;
2133        }
2134     }
2135        }
2136        while (tmplLine->numElements)
2137     removeElement(tmplLine, 0);
2138        if (tmplLine->elements)
2139     free(tmplLine->elements);
2140    
2141        tmplLine->numElements = newLine.numElements;
2142        tmplLine->elements = newLine.elements;
2143    }
2144    
2145    static void insertElement(struct singleLine * line,
2146      const char * item, int insertHere,
2147      struct configFileInfo * cfi)
2148    {
2149        struct keywordTypes * kw;
2150        char indent[2] = "";
2151    
2152        /* sanity check */
2153        if (insertHere > line->numElements) {
2154     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2155      insertHere, line->numElements);
2156     insertHere = line->numElements;
2157        }
2158    
2159        line->elements = realloc(line->elements, (line->numElements + 1) *
2160         sizeof(*line->elements));
2161        memmove(&line->elements[insertHere+1],
2162        &line->elements[insertHere],
2163        (line->numElements - insertHere) *
2164        sizeof(*line->elements));
2165        line->elements[insertHere].item = strdup(item);
2166    
2167        kw = getKeywordByType(line->type, cfi);
2168    
2169        if (line->numElements == 0) {
2170     indent[0] = '\0';
2171        } else if (insertHere == 0) {
2172     indent[0] = kw->nextChar;
2173        } else if (kw->separatorChar != '\0') {
2174     indent[0] = kw->separatorChar;
2175        } else {
2176     indent[0] = ' ';
2177        }
2178    
2179        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2180     /* move the end-of-line forward */
2181     line->elements[insertHere].indent =
2182        line->elements[insertHere-1].indent;
2183     line->elements[insertHere-1].indent = strdup(indent);
2184        } else {
2185     line->elements[insertHere].indent = strdup(indent);
2186        }
2187    
2188        line->numElements++;
2189    
2190        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2191          line->elements[0].item,
2192          line->elements[insertHere].item,
2193          line->elements[insertHere].indent,
2194          insertHere);
2195    }
2196    
2197    static void removeElement(struct singleLine * line, int removeHere) {
2198        int i;
2199    
2200        /* sanity check */
2201        if (removeHere >= line->numElements) return;
2202    
2203        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2204          removeHere, line->elements[removeHere].item);
2205    
2206        free(line->elements[removeHere].item);
2207    
2208        if (removeHere > 1) {
2209     /* previous argument gets this argument's post-indentation */
2210     free(line->elements[removeHere-1].indent);
2211     line->elements[removeHere-1].indent =
2212        line->elements[removeHere].indent;
2213        } else {
2214     free(line->elements[removeHere].indent);
2215        }
2216    
2217        /* now collapse the array, but don't bother to realloc smaller */
2218        for (i = removeHere; i < line->numElements - 1; i++)
2219     line->elements[i] = line->elements[i + 1];
2220    
2221        line->numElements--;
2222    }
2223    
2224  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2225      char * first, * second;      char * first, * second;
2226      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2243  int updateActualImage(struct grubConfig
2243      struct singleEntry * entry;      struct singleEntry * entry;
2244      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2245      int index = 0;      int index = 0;
2246      int i, j, k;      int i, k;
2247      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2248      const char ** arg;      const char ** arg;
2249      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2250      int firstElement;      int firstElement;
2251      int *usedElements, *usedArgs;      int *usedElements;
2252        int doreplace;
2253    
2254      if (!image) return 0;      if (!image) return 0;
2255    
# Line 1609  int updateActualImage(struct grubConfig Line 2276  int updateActualImage(struct grubConfig
2276   }   }
2277      }      }
2278    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2279    
2280      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2281   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2282    
2283      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2284   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2285    
2286      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2287    
2288      k = 0;   if (multibootArgs && !entry->multiboot)
2289      for (arg = newArgs; *arg; arg++)      continue;
2290          k++;  
2291      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2292     * LT_KERNELARGS, use that.  Otherwise use
2293     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2294     */
2295     if (useKernelArgs) {
2296        line = getLineByType(LT_KERNELARGS, entry->lines);
2297        if (!line) {
2298     /* no LT_KERNELARGS, need to add it */
2299     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2300           cfg->secondaryIndent, NULL);
2301        }
2302        firstElement = 1;
2303    
2304      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2305   index++;      line = getLineByType(LT_HYPER, entry->lines);
2306        if (!line) {
2307     /* a multiboot entry without LT_HYPER? */
2308     continue;
2309        }
2310        firstElement = 2;
2311    
2312   line = entry->lines;   } else {
2313   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2314   if (!line) continue;      if (!line) {
2315   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2316     continue;
2317          if (entry->multiboot && !multibootArgs) {      }
2318              /* 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;  
2319   }   }
2320    
2321   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2322      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2323      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2324     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2325        /* this is a multiboot entry, make sure there's
2326         * -- on the args line
2327         */
2328        for (i = firstElement; i < line->numElements; i++) {
2329     if (!strcmp(line->elements[i].item, "--"))
2330        break;
2331        }
2332        if (i == line->numElements) {
2333     /* assume all existing args are kernel args,
2334     * prepend -- to make it official
2335     */
2336     insertElement(line, "--", firstElement, cfg->cfi);
2337     i = firstElement;
2338        }
2339        if (!multibootArgs) {
2340     /* kernel args start after the -- */
2341     firstElement = i + 1;
2342        }
2343     } else if (cfg->cfi->mbConcatArgs) {
2344        /* this is a non-multiboot entry, remove hyper args */
2345        for (i = firstElement; i < line->numElements; i++) {
2346     if (!strcmp(line->elements[i].item, "--"))
2347        break;
2348        }
2349        if (i < line->numElements) {
2350     /* remove args up to -- */
2351     while (strcmp(line->elements[firstElement].item, "--"))
2352        removeElement(line, firstElement);
2353     /* remove -- */
2354     removeElement(line, firstElement);
2355        }
2356   }   }
2357    
2358          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2359    
2360          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2361   for (arg = newArgs; *arg; arg++) {  
2362              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2363      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2364     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2365        !strcmp(line->elements[i].item, "--"))
2366     {
2367        /* reached the end of hyper args, insert here */
2368        doreplace = 0;
2369        break;  
2370     }
2371                  if (usedElements[i])                  if (usedElements[i])
2372                      continue;                      continue;
2373   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2374                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2375      break;      break;
2376                  }                  }
2377              }              }
     chptr = strchr(*arg, '=');  
2378    
2379      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2380   /* replace */   /* direct replacement */
2381   free(line->elements[i].item);   free(line->elements[i].item);
2382   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("");  
  }  
2383    
2384   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2385   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2386      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2387   /* append */   if (rootLine) {
2388   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2389   (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(" ");  
2390   } else {   } else {
2391      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2392         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2393   }   }
2394        }
2395    
2396   line->numElements++;      else {
2397     /* insert/append */
2398     insertElement(line, *arg, i, cfg->cfi);
2399     usedElements = realloc(usedElements, line->numElements *
2400           sizeof(*usedElements));
2401     memmove(&usedElements[i + 1], &usedElements[i],
2402     line->numElements - i - 1);
2403     usedElements[i] = 1;
2404    
2405   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2406     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2407     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2408   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2409      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2410      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2411   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2412   }   }
2413      }      }
             k++;  
2414   }   }
2415    
2416          free(usedElements);          free(usedElements);
2417    
  /* 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? */  
2418   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2419      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2420   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2421        !strcmp(line->elements[i].item, "--"))
2422        /* reached the end of hyper args, stop here */
2423        break;
2424     if (!argMatch(line->elements[i].item, *arg)) {
2425        removeElement(line, i);
2426      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;  
2427   }   }
2428        }
2429   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2430        if (useRoot && !strncmp(*arg, "root=", 5)) {
2431   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2432      line->elements[j - 1] = line->elements[j];   if (rootLine)
2433        removeLine(entry, rootLine);
  line->numElements--;  
2434      }      }
2435   }   }
2436    
# Line 1760  int updateActualImage(struct grubConfig Line 2441  int updateActualImage(struct grubConfig
2441   }   }
2442      }      }
2443    
     free(usedArgs);  
2444      free(newArgs);      free(newArgs);
2445      free(oldArgs);      free(oldArgs);
2446    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2466  int updateImage(struct grubConfig * cfg,
2466      return rc;      return rc;
2467  }  }
2468    
2469    int updateInitrd(struct grubConfig * cfg, const char * image,
2470                     const char * prefix, const char * initrd) {
2471        struct singleEntry * entry;
2472        struct singleLine * line, * kernelLine, *endLine = NULL;
2473        int index = 0;
2474    
2475        if (!image) return 0;
2476    
2477        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2478            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2479            if (!kernelLine) continue;
2480    
2481            line = getLineByType(LT_INITRD, entry->lines);
2482            if (line)
2483                removeLine(entry, line);
2484            if (prefix) {
2485                int prefixLen = strlen(prefix);
2486                if (!strncmp(initrd, prefix, prefixLen))
2487                    initrd += prefixLen;
2488            }
2489     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2490     if (endLine)
2491        removeLine(entry, endLine);
2492            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2493            if (!line)
2494        return 1;
2495     if (endLine) {
2496        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2497                if (!line)
2498     return 1;
2499     }
2500    
2501            break;
2502        }
2503    
2504        return 0;
2505    }
2506    
2507  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2508      int fd;      int fd;
2509      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2527  int checkDeviceBootloader(const char * d
2527      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2528   return 0;   return 0;
2529    
2530      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2531   offset = boot[2] + 2;   offset = boot[2] + 2;
2532      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2533   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2534      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2535   offset = boot[1] + 2;        offset = boot[1] + 2;
2536            /*
2537     * it looks like grub, when copying stage1 into the mbr, patches stage1
2538     * right after the JMP location, replacing other instructions such as
2539     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2540     * different bytes.
2541     */
2542          if ((bootSect[offset + 1] == NOOP_OPCODE)
2543      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2544     offset = offset + 3;
2545          }
2546      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2547   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2548      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2684  int checkForLilo(struct grubConfig * con
2684      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2685  }  }
2686    
2687    int checkForGrub2(struct grubConfig * config) {
2688        if (!access("/etc/grub.d/", R_OK))
2689     return 2;
2690    
2691        return 1;
2692    }
2693    
2694  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2695      int fd;      int fd;
2696      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2711  int checkForGrub(struct grubConfig * con
2711      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2712   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2713   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2714     close(fd);
2715     return 1;
2716        }
2717        close(fd);
2718    
2719        return checkDeviceBootloader(boot, bootSect);
2720    }
2721    
2722    int checkForExtLinux(struct grubConfig * config) {
2723        int fd;
2724        unsigned char bootSect[512];
2725        char * boot;
2726        char executable[] = "/boot/extlinux/extlinux";
2727    
2728        printf("entered: checkForExtLinux()\n");
2729    
2730        if (parseSysconfigGrub(NULL, &boot))
2731     return 0;
2732    
2733        /* assume grub is not installed -- not an error condition */
2734        if (!boot)
2735     return 0;
2736    
2737        fd = open(executable, O_RDONLY);
2738        if (fd < 0)
2739     /* this doesn't exist if grub hasn't been installed */
2740     return 0;
2741    
2742        if (read(fd, bootSect, 512) != 512) {
2743     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2744     executable, strerror(errno));
2745   return 1;   return 1;
2746      }      }
2747      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2760  static char * getRootSpecifier(char * st
2760      return rootspec;      return rootspec;
2761  }  }
2762    
2763    static char * getInitrdVal(struct grubConfig * config,
2764       const char * prefix, struct singleLine *tmplLine,
2765       const char * newKernelInitrd,
2766       char ** extraInitrds, int extraInitrdCount)
2767    {
2768        char *initrdVal, *end;
2769        int i;
2770        size_t totalSize;
2771        size_t prefixLen;
2772        char separatorChar;
2773    
2774        prefixLen = strlen(prefix);
2775        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2776    
2777        for (i = 0; i < extraInitrdCount; i++) {
2778     totalSize += sizeof(separatorChar);
2779     totalSize += strlen(extraInitrds[i]) - prefixLen;
2780        }
2781    
2782        initrdVal = end = malloc(totalSize);
2783    
2784        end = stpcpy (end, newKernelInitrd + prefixLen);
2785    
2786        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2787        for (i = 0; i < extraInitrdCount; i++) {
2788     const char *extraInitrd;
2789     int j;
2790    
2791     extraInitrd = extraInitrds[i] + prefixLen;
2792     /* Don't add entries that are already there */
2793     if (tmplLine != NULL) {
2794        for (j = 2; j < tmplLine->numElements; j++)
2795     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2796        break;
2797    
2798        if (j != tmplLine->numElements)
2799     continue;
2800     }
2801    
2802     *end++ = separatorChar;
2803     end = stpcpy(end, extraInitrd);
2804        }
2805    
2806        return initrdVal;
2807    }
2808    
2809  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2810           const char * prefix,           const char * prefix,
2811   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2812   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2813     char ** extraInitrds, int extraInitrdCount,
2814                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2815      struct singleEntry * new;      struct singleEntry * new;
2816      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2817      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2818      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2819    
2820      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2821    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2845  int addNewKernel(struct grubConfig * con
2845      config->entries = new;      config->entries = new;
2846    
2847      /* copy/update from the template */      /* copy/update from the template */
2848      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2849        if (newKernelInitrd)
2850     needs |= NEED_INITRD;
2851      if (newMBKernel) {      if (newMBKernel) {
2852          needs |= KERNEL_MB;          needs |= NEED_MB;
2853          new->multiboot = 1;          new->multiboot = 1;
2854      }      }
2855    
2856      if (template) {      if (template) {
2857   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2858      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2859      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2860   indent = tmplLine->indent;   {
2861        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2862    
2863      /* skip comments */      /* skip comments */
2864      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2865      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2866      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2867    
2868      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2869      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2870     if (!template->multiboot && (needs & NEED_MB)) {
2871              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2872                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2873                  struct singleLine *l;       * hypervisor at the same time.
2874                  needs &= ~ KERNEL_MB;       */
2875        if (config->cfi->mbHyperFirst) {
2876                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2877                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2878                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2879                      newMBKernel + strlen(prefix));
2880                  tmplLine = lastLine;   /* set up for adding the kernel line */
2881                  if (!new->lines) {   free(tmplLine->indent);
2882                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2883                  } else {   needs &= ~NEED_MB;
2884                      newLine->next = l;      }
2885                      newLine = l;      if (needs & NEED_KERNEL) {
2886                  }   /* use addLineTmpl to preserve line elements,
2887                  continue;   * otherwise we could just call addLine.  Unfortunately
2888              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2889                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2890                  continue; /* don't need multiboot kernel here */   * change below.
2891              }   */
2892     struct keywordTypes * mbm_kw =
2893        getKeywordByType(LT_MBMODULE, config->cfi);
2894     if (mbm_kw) {
2895        tmplLine->type = LT_MBMODULE;
2896        free(tmplLine->elements[0].item);
2897        tmplLine->elements[0].item = strdup(mbm_kw->key);
2898     }
2899     newLine = addLineTmpl(new, tmplLine, newLine,
2900          newKernelPath + strlen(prefix), config->cfi);
2901     needs &= ~NEED_KERNEL;
2902        }
2903        if (needs & NEED_MB) { /* !mbHyperFirst */
2904     newLine = addLine(new, config->cfi, LT_HYPER,
2905      config->secondaryIndent,
2906      newMBKernel + strlen(prefix));
2907     needs &= ~NEED_MB;
2908        }
2909     } else if (needs & NEED_KERNEL) {
2910        newLine = addLineTmpl(new, tmplLine, newLine,
2911      newKernelPath + strlen(prefix), config->cfi);
2912        needs &= ~NEED_KERNEL;
2913     }
2914    
2915      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2916   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2917   new->lines = newLine;   if (needs & NEED_MB) {
2918      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2919   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2920   newLine = newLine->next;      needs &= ~NEED_MB;
2921      }   }
2922    
2923        } else if (tmplLine->type == LT_MBMODULE &&
2924           tmplLine->numElements >= 2) {
2925     if (new->multiboot) {
2926        if (needs & NEED_KERNEL) {
2927     newLine = addLineTmpl(new, tmplLine, newLine,
2928          newKernelPath +
2929          strlen(prefix), config->cfi);
2930     needs &= ~NEED_KERNEL;
2931        } else if (config->cfi->mbInitRdIsModule &&
2932           (needs & NEED_INITRD)) {
2933     char *initrdVal;
2934     initrdVal = getInitrdVal(config, prefix, tmplLine,
2935     newKernelInitrd, extraInitrds,
2936     extraInitrdCount);
2937     newLine = addLineTmpl(new, tmplLine, newLine,
2938          initrdVal, config->cfi);
2939     free(initrdVal);
2940     needs &= ~NEED_INITRD;
2941        }
2942     } else if (needs & NEED_KERNEL) {
2943        /* template is multi but new is not,
2944         * insert the kernel in the first module slot
2945         */
2946        tmplLine->type = LT_KERNEL;
2947        free(tmplLine->elements[0].item);
2948        tmplLine->elements[0].item =
2949     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2950        newLine = addLineTmpl(new, tmplLine, newLine,
2951      newKernelPath + strlen(prefix), config->cfi);
2952        needs &= ~NEED_KERNEL;
2953     } else if (needs & NEED_INITRD) {
2954        char *initrdVal;
2955        /* template is multi but new is not,
2956         * insert the initrd in the second module slot
2957         */
2958        tmplLine->type = LT_INITRD;
2959        free(tmplLine->elements[0].item);
2960        tmplLine->elements[0].item =
2961     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2962        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2963        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2964        free(initrdVal);
2965        needs &= ~NEED_INITRD;
2966     }
2967    
     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));  
                 }  
2968      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2969      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2970   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2971   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2972                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2973                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2974                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2975                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2976                  }       */
2977                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2978                  if (rootspec != NULL) {   char *initrdVal;
2979                      newLine->elements[1].item = sdupprintf("%s%s",  
2980                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2981                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2982                                                             strlen(prefix));    config->secondaryIndent,
2983                  } else {    initrdVal);
2984                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2985                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2986                  }      }
2987              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2988                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2989   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2990                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2991                      free(newLine->elements[0].item);      free(initrdVal);
2992                      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);  
2993   }   }
2994    
2995   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
2996   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
2997   newLine->numElements = 2;   requote(tmplLine, config->cfi);
2998     char *nkt = malloc(strlen(newKernelTitle)+3);
2999     strcpy(nkt, "'");
3000     strcat(nkt, newKernelTitle);
3001     strcat(nkt, "'");
3002     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3003     free(nkt);
3004     needs &= ~NEED_TITLE;
3005      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3006                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3007                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3008                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3009                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3010                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3011                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3012                                             newLine->numElements);     config->cfi->titleBracketed) {
3013        /* addLineTmpl doesn't handle titleBracketed */
3014                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3015                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3016                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3017                  newLine->numElements = 1;   }
3018              }      } else if (tmplLine->type == LT_ECHO) {
3019        requote(tmplLine, config->cfi);
3020        static const char *prefix = "'Loading ";
3021        if (tmplLine->numElements > 1 &&
3022        strstr(tmplLine->elements[1].item, prefix) &&
3023        masterLine->next && masterLine->next->type == LT_KERNEL) {
3024     char *newTitle = malloc(strlen(prefix) +
3025     strlen(newKernelTitle) + 2);
3026    
3027     strcpy(newTitle, prefix);
3028     strcat(newTitle, newKernelTitle);
3029     strcat(newTitle, "'");
3030     newLine = addLine(new, config->cfi, LT_ECHO,
3031     tmplLine->indent, newTitle);
3032     free(newTitle);
3033        } else {
3034     /* pass through other lines from the template */
3035     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3036     config->cfi);
3037        }
3038        } else {
3039     /* pass through other lines from the template */
3040     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3041        }
3042   }   }
3043    
3044      } else {      } else {
3045   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3046      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3047     */
3048     switch (config->cfi->entryStart) {
3049        case LT_KERNEL:
3050     if (new->multiboot && config->cfi->mbHyperFirst) {
3051        /* fall through to LT_HYPER */
3052     } else {
3053        newLine = addLine(new, config->cfi, LT_KERNEL,
3054          config->primaryIndent,
3055          newKernelPath + strlen(prefix));
3056        needs &= ~NEED_KERNEL;
3057        break;
3058     }
3059    
3060        case LT_HYPER:
3061     newLine = addLine(new, config->cfi, LT_HYPER,
3062      config->primaryIndent,
3063      newMBKernel + strlen(prefix));
3064     needs &= ~NEED_MB;
3065   break;   break;
         }  
3066    
3067   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3068      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3069       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3070       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3071      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3072       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3073      default:        config->primaryIndent, nkt);
3074                  /* zipl strikes again */   free(nkt);
3075                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3076                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3077                      chptr = newKernelTitle;   break;
3078                      type = LT_TITLE;      }
3079                      break;      case LT_TITLE:
3080                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3081                      abort();   char * templabel;
3082                  }   int x = 0, y = 0;
3083   }  
3084     templabel = strdup(newKernelTitle);
3085     while( templabel[x]){
3086     if( templabel[x] == ' ' ){
3087     y = x;
3088     while( templabel[y] ){
3089     templabel[y] = templabel[y+1];
3090     y++;
3091     }
3092     }
3093     x++;
3094     }
3095     newLine = addLine(new, config->cfi, LT_TITLE,
3096      config->primaryIndent, templabel);
3097     free(templabel);
3098     }else{
3099     newLine = addLine(new, config->cfi, LT_TITLE,
3100      config->primaryIndent, newKernelTitle);
3101     }
3102     needs &= ~NEED_TITLE;
3103     break;
3104    
3105   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3106   new->lines = newLine;   abort();
3107     }
3108      }      }
3109    
3110      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3111          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3112              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3113                                config->secondaryIndent,       */
3114                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3115          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3116              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3117                                config->secondaryIndent,    newKernelTitle);
3118                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3119          /* don't need to check for title as it's guaranteed to have been      }
3120           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3121           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3122          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3123              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3124                                config->secondaryIndent,   needs &= ~NEED_MB;
3125                                newKernelInitrd + strlen(prefix));      }
3126      } else {      if (needs & NEED_KERNEL) {
3127          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3128              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3129                                config->secondaryIndent,        config->cfi)) ?
3130                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3131          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3132              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3133                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3134                                newKernelTitle);      }
3135          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3136              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3137                                config->secondaryIndent,    config->secondaryIndent,
3138                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3139     needs &= ~NEED_MB;
3140        }
3141        if (needs & NEED_INITRD) {
3142     char *initrdVal;
3143     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3144     newLine = addLine(new, config->cfi,
3145      (new->multiboot && getKeywordByType(LT_MBMODULE,
3146          config->cfi)) ?
3147      LT_MBMODULE : LT_INITRD,
3148      config->secondaryIndent,
3149      initrdVal);
3150     free(initrdVal);
3151     needs &= ~NEED_INITRD;
3152        }
3153        if (needs & NEED_END) {
3154     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3155     config->secondaryIndent, NULL);
3156     needs &= ~NEED_END;
3157        }
3158    
3159        if (needs) {
3160     printf(_("grubby: needs=%d, aborting\n"), needs);
3161     abort();
3162      }      }
3163    
3164      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3167  int addNewKernel(struct grubConfig * con
3167      return 0;      return 0;
3168  }  }
3169    
3170    static void traceback(int signum)
3171    {
3172        void *array[40];
3173        size_t size;
3174    
3175        signal(SIGSEGV, SIG_DFL);
3176        memset(array, '\0', sizeof (array));
3177        size = backtrace(array, 40);
3178    
3179        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3180                (unsigned long)size);
3181        backtrace_symbols_fd(array, size, STDERR_FILENO);
3182        exit(1);
3183    }
3184    
3185  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3186      poptContext optCon;      poptContext optCon;
3187      char * grubConfig = NULL;      const char * grubConfig = NULL;
3188      char * outputFile = NULL;      char * outputFile = NULL;
3189      int arg = 0;      int arg = 0;
3190      int flags = 0;      int flags = 0;
3191      int badImageOkay = 0;      int badImageOkay = 0;
3192        int configureGrub2 = 0;
3193      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3194      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3195        int configureExtLinux = 0;
3196      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3197        int extraInitrdCount = 0;
3198      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3199      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3200      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3210  int main(int argc, const char ** argv) {
3210      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3211      char * removeArgs = NULL;      char * removeArgs = NULL;
3212      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3213        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3214      const char * chptr = NULL;      const char * chptr = NULL;
3215      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3216      struct grubConfig * config;      struct grubConfig * config;
3217      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3218      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3219      int displayDefault = 0;      int displayDefault = 0;
3220        int displayDefaultIndex = 0;
3221        int displayDefaultTitle = 0;
3222      struct poptOption options[] = {      struct poptOption options[] = {
3223   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3224      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2335  int main(int argc, const char ** argv) { Line 3249  int main(int argc, const char ** argv) {
3249        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3250        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3251        "template"), NULL },        "template"), NULL },
3252     { "debug", 0, 0, &debug, 0,
3253        _("print debugging information for failures") },
3254   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3255      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3256     { "default-index", 0, 0, &displayDefaultIndex, 0,
3257        _("display the index of the default kernel") },
3258     { "default-title", 0, 0, &displayDefaultTitle, 0,
3259        _("display the title of the default kernel") },
3260   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3261      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3262     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3263        _("configure extlinux bootloader (from syslinux)") },
3264   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3265      _("configure grub bootloader") },      _("configure grub bootloader") },
3266     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3267        _("configure grub2 bootloader") },
3268   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3269      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3270      _("kernel-path") },      _("kernel-path") },
3271   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3272      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3273     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3274        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3275   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3276      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3277   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3308  int main(int argc, const char ** argv) {
3308   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3309      };      };
3310    
3311        useextlinuxmenu=0;
3312    
3313        signal(SIGSEGV, traceback);
3314    
3315      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3316      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3317    
# Line 2391  int main(int argc, const char ** argv) { Line 3321  int main(int argc, const char ** argv) {
3321      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3322      exit(0);      exit(0);
3323      break;      break;
3324      case 'i':
3325        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3326         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3327        } else {
3328     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3329     return 1;
3330        }
3331        break;
3332   }   }
3333      }      }
3334    
# Line 2406  int main(int argc, const char ** argv) { Line 3344  int main(int argc, const char ** argv) {
3344   return 1;   return 1;
3345      }      }
3346    
3347      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3348   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3349     configureExtLinux ) > 1) {
3350   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3351   return 1;   return 1;
3352      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3353   fprintf(stderr,   fprintf(stderr,
3354      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3355   return 1;   return 1;
3356        } else if (configureGrub2) {
3357     cfi = &grub2ConfigType;
3358      } else if (configureLilo) {      } else if (configureLilo) {
3359   cfi = &liloConfigType;   cfi = &liloConfigType;
3360      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3367  int main(int argc, const char ** argv) {
3367          cfi = &siloConfigType;          cfi = &siloConfigType;
3368      } else if (configureZipl) {      } else if (configureZipl) {
3369          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3370        } else if (configureExtLinux) {
3371     cfi = &extlinuxConfigType;
3372     useextlinuxmenu=1;
3373      }      }
3374    
3375      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3384  int main(int argc, const char ** argv) {
3384        #elif __s390x__        #elif __s390x__
3385          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3386        #else        #else
3387   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3388        cfi = &grub2ConfigType;
3389     else
3390        cfi = &grubConfigType;
3391        #endif        #endif
3392      }      }
3393    
3394      if (!grubConfig)      if (!grubConfig) {
3395   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3396        grubConfig = cfi->findConfig(cfi);
3397     if (!grubConfig)
3398        grubConfig = cfi->defaultConfig;
3399        }
3400    
3401      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3402    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3403    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3404   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3405    "specified option"));    "specified option"));
3406   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3416  int main(int argc, const char ** argv) {
3416      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3417   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3418   return 1;   return 1;
3419      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3420    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3421    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3422   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3423   return 1;   return 1;
3424      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3443  int main(int argc, const char ** argv) {
3443   defaultKernel = NULL;   defaultKernel = NULL;
3444      }      }
3445    
3446      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3447   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3448   "is used\n"));   "is used\n"));
3449   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3451  int main(int argc, const char ** argv) {
3451    
3452      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3453   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3454          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3455   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3456   return 1;   return 1;
3457      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3471  int main(int argc, const char ** argv) {
3471   bootPrefix = "";   bootPrefix = "";
3472      }      }
3473    
3474        if (!cfi->mbAllowExtraInitRds &&
3475     extraInitrdCount > 0) {
3476     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3477     return 1;
3478        }
3479    
3480      if (bootloaderProbe) {      if (bootloaderProbe) {
3481   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3482   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3483    
3484   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3485      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3486        gconfig = readConfig(grub2config, &grub2ConfigType);
3487        if (!gconfig)
3488     gr2c = 1;
3489        else
3490     gr2c = checkForGrub2(gconfig);
3491     }
3492    
3493     const char *grubconfig = grubFindConfig(&grubConfigType);
3494     if (!access(grubconfig, F_OK)) {
3495        gconfig = readConfig(grubconfig, &grubConfigType);
3496      if (!gconfig)      if (!gconfig)
3497   grc = 1;   grc = 1;
3498      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3507  int main(int argc, const char ** argv) {
3507   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3508   }   }
3509    
3510   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3511        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3512        if (!lconfig)
3513     erc = 1;
3514        else
3515     erc = checkForExtLinux(lconfig);
3516     }
3517    
3518     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3519    
3520   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3521     if (gr2c == 2) printf("grub2\n");
3522   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3523     if (erc == 2) printf("extlinux\n");
3524    
3525   return 0;   return 0;
3526      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3538  int main(int argc, const char ** argv) {
3538   if (!entry) return 0;   if (!entry) return 0;
3539   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3540    
3541   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3542   if (!line) return 0;   if (!line) return 0;
3543    
3544          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3546  int main(int argc, const char ** argv) {
3546                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3547    
3548   return 0;   return 0;
3549    
3550        } else if (displayDefaultTitle) {
3551     struct singleLine * line;
3552     struct singleEntry * entry;
3553    
3554     if (config->defaultImage == -1) return 0;
3555     entry = findEntryByIndex(config, config->defaultImage);
3556     if (!entry) return 0;
3557    
3558     if (!configureGrub2) {
3559      line = getLineByType(LT_TITLE, entry->lines);
3560      if (!line) return 0;
3561      printf("%s\n", line->elements[1].item);
3562    
3563     } else {
3564      int i;
3565      size_t len;
3566      char * start;
3567      char * tmp;
3568    
3569      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3570      line = getLineByType(LT_MENUENTRY, entry->lines);
3571      if (!line) return 0;
3572    
3573      for (i = 0; i < line->numElements; i++) {
3574    
3575        if (!strcmp(line->elements[i].item, "menuentry"))
3576          continue;
3577    
3578        if (*line->elements[i].item == '\'')
3579          start = line->elements[i].item + 1;
3580        else
3581          start = line->elements[i].item;
3582    
3583        len = strlen(start);
3584        if (*(start + len - 1) == '\'') {
3585          tmp = strdup(start);
3586          *(tmp + len - 1) = '\0';
3587          printf("%s", tmp);
3588          free(tmp);
3589          break;
3590        } else {
3591          printf("%s ", start);
3592        }
3593      }
3594      printf("\n");
3595     }
3596     return 0;
3597    
3598        } else if (displayDefaultIndex) {
3599            if (config->defaultImage == -1) return 0;
3600            printf("%i\n", config->defaultImage);
3601    
3602      } else if (kernelInfo)      } else if (kernelInfo)
3603   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3604    
# Line 2585  int main(int argc, const char ** argv) { Line 3614  int main(int argc, const char ** argv) {
3614      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3615      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3616                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3617        if (updateKernelPath && newKernelInitrd) {
3618                if (updateInitrd(config, updateKernelPath, bootPrefix,
3619                                 newKernelInitrd)) return 1;
3620        }
3621      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3622                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3623                         extraInitrds, extraInitrdCount,
3624                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3625            
3626    
# Line 2597  int main(int argc, const char ** argv) { Line 3631  int main(int argc, const char ** argv) {
3631      }      }
3632    
3633      if (!outputFile)      if (!outputFile)
3634   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3635    
3636      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3637  }  }

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