Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1745 by niro, Sat Feb 18 01:05:52 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    #define beginswith(s, c) ((s) && (s)[0] == (c))
1372    
1373    static int endswith(const char *s, char c)
1374    {
1375     int slen;
1376    
1377     if (!s && !s[0])
1378     return 0;
1379     slen = strlen(s) - 1;
1380    
1381     return s[slen] == c;
1382    }
1383    
1384  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1385    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1386      struct singleLine * line;      struct singleLine * line;
1387      char * fullName;      char * fullName;
1388      int i;      int i;
     struct stat sb, sb2;  
1389      char * dev;      char * dev;
     char * end;  
1390      char * rootspec;      char * rootspec;
1391        char * rootdev;
1392    
1393      line = entry->lines;      if (skipRemoved && entry->skip) {
1394      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1395         return 0;
1396      if (!line) return 0;      }
1397      if (skipRemoved && entry->skip) return 0;  
1398      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1399        if (!line) {
1400     notSuitablePrintf(entry, "no line found\n");
1401     return 0;
1402        }
1403        if (line->numElements < 2) {
1404     notSuitablePrintf(entry, "line has only %d elements\n",
1405        line->numElements);
1406     return 0;
1407        }
1408    
1409      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1410    
1411      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1412        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1413      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1414      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1415              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1416                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1417      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1418                line->elements[1].item + rootspec_offset);
1419        if (access(fullName, R_OK)) {
1420     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1421     return 0;
1422        }
1423      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1424   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1425      if (i < line->numElements) {      if (i < line->numElements) {
1426   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1427      } else {      } else {
1428   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1429   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1430    
1431   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1432      dev = line->elements[1].item;      dev = line->elements[1].item;
1433   } else {   } else {
1434              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1435      /* 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.
1436      line = entry->lines;       */
1437        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1438    
1439              /* failed to find one */              /* failed to find one */
1440              if (!line) return 0;              if (!line) {
1441     notSuitablePrintf(entry, "no line found\n");
1442     return 0;
1443                }
1444    
1445      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1446          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1447      if (i < line->numElements)      if (i < line->numElements)
1448          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1449      else {      else {
1450     notSuitablePrintf(entry, "no root= entry found\n");
1451   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1452          return 0;          return 0;
1453              }              }
1454   }   }
1455      }      }
1456    
1457      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1458   dev += 6;      if (!getpathbyspec(dev)) {
1459            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1460   /* check which device has this label */          return 0;
1461   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1462   if (!dev) return 0;   dev = getpathbyspec(dev);
1463    
1464        rootdev = findDiskForRoot();
1465        if (!rootdev) {
1466            notSuitablePrintf(entry, "can't find root device\n");
1467     return 0;
1468      }      }
1469    
1470      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1471   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1472      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1473      } else {          free(rootdev);
1474   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1475   if (*end) return 0;      }
1476    
1477        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1478            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1479     getuuidbydev(rootdev), getuuidbydev(dev));
1480     free(rootdev);
1481            return 0;
1482      }      }
     stat("/", &sb2);  
1483    
1484      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1485    
1486      return 1;      return 1;
1487  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1525  struct singleEntry * findEntryByPath(str
1525   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1526   if (!entry) return NULL;   if (!entry) return NULL;
1527    
1528   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1529   if (!line) return NULL;   if (!line) return NULL;
1530    
1531   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1567  struct singleEntry * findEntryByPath(str
1567      kernel += 6;      kernel += 6;
1568   }   }
1569    
1570   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1571      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1572    
1573        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1574    
1575      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1576                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1577          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1578                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1579                              kernel + strlen(prefix)))       checkType, line);
1580                      break;   if (!line) break;  /* not found in this entry */
1581              }  
1582                 if (line && line->numElements >= 2) {
1583              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1584              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1585                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1586                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1587                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1588                      if (!strcmp(line->elements[1].item  +   }
1589                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1590    
1591      i++;      /* make sure this entry has a kernel identifier; this skips
1592         * non-Linux boot entries (could find netbsd etc, though, which is
1593         * unfortunate)
1594         */
1595        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1596     break; /* found 'im! */
1597   }   }
1598    
1599   if (index) *index = i;   if (index) *index = i;
1600      }      }
1601    
     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);  
     }  
   
1602      return entry;      return entry;
1603  }  }
1604    
# Line 1286  void displayEntry(struct singleEntry * e Line 1763  void displayEntry(struct singleEntry * e
1763      char * root = NULL;      char * root = NULL;
1764      int i;      int i;
1765    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1766      printf("index=%d\n", index);      printf("index=%d\n", index);
1767    
1768        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1769        if (!line) {
1770            printf("non linux entry\n");
1771            return;
1772        }
1773    
1774      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1775    
1776      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1788  void displayEntry(struct singleEntry * e
1788   }   }
1789   printf("\"\n");   printf("\"\n");
1790      } else {      } else {
1791   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1792   if (line) {   if (line) {
1793      char * s;      char * s;
1794    
# Line 1334  void displayEntry(struct singleEntry * e Line 1812  void displayEntry(struct singleEntry * e
1812      }      }
1813    
1814      if (!root) {      if (!root) {
1815   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1816   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1817      root=line->elements[1].item;      root=line->elements[1].item;
1818      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1827  void displayEntry(struct singleEntry * e
1827   printf("root=%s\n", s);   printf("root=%s\n", s);
1828      }      }
1829    
1830      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1831    
1832      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1833   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1844  int parseSysconfigGrub(int * lbaPtr, cha
1844      char * start;      char * start;
1845      char * param;      char * param;
1846    
1847      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1848      if (!in) return 1;      if (!in) return 1;
1849    
1850      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1906  int displayInfo(struct grubConfig * conf
1906   return 1;   return 1;
1907      }      }
1908    
1909      /* 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
1910         be a better way */         be a better way */
1911      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1912   dumpSysconfigGrub();   dumpSysconfigGrub();
1913      } else {      } else {
1914   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1915   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1916      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1917   }   }
1918    
1919   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1920   if (line) printf("lba\n");   if (line) printf("lba\n");
1921      }      }
1922    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1931  int displayInfo(struct grubConfig * conf
1931      return 0;      return 0;
1932  }  }
1933    
1934    struct singleLine * addLineTmpl(struct singleEntry * entry,
1935     struct singleLine * tmplLine,
1936     struct singleLine * prevLine,
1937     const char * val,
1938     struct configFileInfo * cfi)
1939    {
1940        struct singleLine * newLine = lineDup(tmplLine);
1941    
1942        if (val) {
1943     /* override the inherited value with our own.
1944     * This is a little weak because it only applies to elements[1]
1945     */
1946     if (newLine->numElements > 1)
1947        removeElement(newLine, 1);
1948     insertElement(newLine, val, 1, cfi);
1949    
1950     /* but try to keep the rootspec from the template... sigh */
1951     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1952        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1953        if (rootspec != NULL) {
1954     free(newLine->elements[1].item);
1955     newLine->elements[1].item =
1956        sdupprintf("%s%s", rootspec, val);
1957        }
1958     }
1959        }
1960    
1961        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1962          newLine->elements[0].item : "");
1963    
1964        if (!entry->lines) {
1965     /* first one on the list */
1966     entry->lines = newLine;
1967        } else if (prevLine) {
1968     /* add after prevLine */
1969     newLine->next = prevLine->next;
1970     prevLine->next = newLine;
1971        }
1972    
1973        return newLine;
1974    }
1975    
1976  /* val may be NULL */  /* val may be NULL */
1977  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1978       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1979       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1980       char * val) {       const char * val) {
1981      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1982      int i;      struct keywordTypes * kw;
1983        struct singleLine tmpl;
1984    
1985      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1986   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1987      if (type != LT_TITLE || !cfi->titleBracketed)       */
1988          if (!cfi->keywords[i].key) abort();  
1989        if (type == LT_TITLE && cfi->titleBracketed) {
1990     /* we're doing a bracketed title (zipl) */
1991     tmpl.type = type;
1992     tmpl.numElements = 1;
1993     tmpl.elements = alloca(sizeof(*tmpl.elements));
1994     tmpl.elements[0].item = alloca(strlen(val)+3);
1995     sprintf(tmpl.elements[0].item, "[%s]", val);
1996     tmpl.elements[0].indent = "";
1997     val = NULL;
1998        } else if (type == LT_MENUENTRY) {
1999     char *lineend = "--class gnu-linux --class gnu --class os {";
2000     if (!val) {
2001        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2002        abort();
2003     }
2004     kw = getKeywordByType(type, cfi);
2005     if (!kw) {
2006        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2007        abort();
2008     }
2009     tmpl.indent = "";
2010     tmpl.type = type;
2011     tmpl.numElements = 3;
2012     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2013     tmpl.elements[0].item = kw->key;
2014     tmpl.elements[0].indent = alloca(2);
2015     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2016     tmpl.elements[1].item = (char *)val;
2017     tmpl.elements[1].indent = alloca(2);
2018     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2019     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2020     strcpy(tmpl.elements[2].item, lineend);
2021     tmpl.elements[2].indent = "";
2022        } else {
2023     kw = getKeywordByType(type, cfi);
2024     if (!kw) {
2025        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2026        abort();
2027     }
2028     tmpl.type = type;
2029     tmpl.numElements = val ? 2 : 1;
2030     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2031     tmpl.elements[0].item = kw->key;
2032     tmpl.elements[0].indent = alloca(2);
2033     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2034     if (val) {
2035        tmpl.elements[1].item = (char *)val;
2036        tmpl.elements[1].indent = "";
2037     }
2038        }
2039    
2040      /* 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
2041         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2042         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
2043         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2044         differently from the rest) */         differently from the rest) */
2045      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2046   line = entry->lines;   if (line->numElements) prev = line;
2047   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2048   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;  
2049      }      }
2050    
2051      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2052          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2053          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2054          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2055          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2056          line->elements[0].indent = malloc(2);   else
2057          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2058          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2059             if (menuEntry)
2060          if (val) {      tmpl.indent = "\t";
2061              line->elements[1].item = val;   else if (prev == entry->lines)
2062              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2063          }   else
2064      } 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("");  
2065      }      }
2066    
2067      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2068  }  }
2069    
2070  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2089  void removeLine(struct singleEntry * ent
2089      free(line);      free(line);
2090  }  }
2091    
2092    static int isquote(char q)
2093    {
2094        if (q == '\'' || q == '\"')
2095     return 1;
2096        return 0;
2097    }
2098    
2099    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2100    {
2101        struct singleLine newLine = {
2102     .indent = tmplLine->indent,
2103     .type = tmplLine->type,
2104     .next = tmplLine->next,
2105        };
2106        int firstQuotedItem = -1;
2107        int quoteLen = 0;
2108        int j;
2109        int element = 0;
2110        char *c;
2111    
2112        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2113        strcpy(c, tmplLine->elements[0].item);
2114        insertElement(&newLine, c, element++, cfi);
2115        free(c);
2116        c = NULL;
2117    
2118        for (j = 1; j < tmplLine->numElements; j++) {
2119     if (firstQuotedItem == -1) {
2120        quoteLen += strlen(tmplLine->elements[j].item);
2121        
2122        if (isquote(tmplLine->elements[j].item[0])) {
2123     firstQuotedItem = j;
2124            quoteLen += strlen(tmplLine->elements[j].indent);
2125        } else {
2126     c = malloc(quoteLen + 1);
2127     strcpy(c, tmplLine->elements[j].item);
2128     insertElement(&newLine, c, element++, cfi);
2129     free(c);
2130     quoteLen = 0;
2131        }
2132     } else {
2133        int itemlen = strlen(tmplLine->elements[j].item);
2134        quoteLen += itemlen;
2135        quoteLen += strlen(tmplLine->elements[j].indent);
2136        
2137        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2138     c = malloc(quoteLen + 1);
2139     c[0] = '\0';
2140     for (int i = firstQuotedItem; i < j+1; i++) {
2141        strcat(c, tmplLine->elements[i].item);
2142        strcat(c, tmplLine->elements[i].indent);
2143     }
2144     insertElement(&newLine, c, element++, cfi);
2145     free(c);
2146    
2147     firstQuotedItem = -1;
2148     quoteLen = 0;
2149        }
2150     }
2151        }
2152        while (tmplLine->numElements)
2153     removeElement(tmplLine, 0);
2154        if (tmplLine->elements)
2155     free(tmplLine->elements);
2156    
2157        tmplLine->numElements = newLine.numElements;
2158        tmplLine->elements = newLine.elements;
2159    }
2160    
2161    static void insertElement(struct singleLine * line,
2162      const char * item, int insertHere,
2163      struct configFileInfo * cfi)
2164    {
2165        struct keywordTypes * kw;
2166        char indent[2] = "";
2167    
2168        /* sanity check */
2169        if (insertHere > line->numElements) {
2170     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2171      insertHere, line->numElements);
2172     insertHere = line->numElements;
2173        }
2174    
2175        line->elements = realloc(line->elements, (line->numElements + 1) *
2176         sizeof(*line->elements));
2177        memmove(&line->elements[insertHere+1],
2178        &line->elements[insertHere],
2179        (line->numElements - insertHere) *
2180        sizeof(*line->elements));
2181        line->elements[insertHere].item = strdup(item);
2182    
2183        kw = getKeywordByType(line->type, cfi);
2184    
2185        if (line->numElements == 0) {
2186     indent[0] = '\0';
2187        } else if (insertHere == 0) {
2188     indent[0] = kw->nextChar;
2189        } else if (kw->separatorChar != '\0') {
2190     indent[0] = kw->separatorChar;
2191        } else {
2192     indent[0] = ' ';
2193        }
2194    
2195        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2196     /* move the end-of-line forward */
2197     line->elements[insertHere].indent =
2198        line->elements[insertHere-1].indent;
2199     line->elements[insertHere-1].indent = strdup(indent);
2200        } else {
2201     line->elements[insertHere].indent = strdup(indent);
2202        }
2203    
2204        line->numElements++;
2205    
2206        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2207          line->elements[0].item,
2208          line->elements[insertHere].item,
2209          line->elements[insertHere].indent,
2210          insertHere);
2211    }
2212    
2213    static void removeElement(struct singleLine * line, int removeHere) {
2214        int i;
2215    
2216        /* sanity check */
2217        if (removeHere >= line->numElements) return;
2218    
2219        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2220          removeHere, line->elements[removeHere].item);
2221    
2222        free(line->elements[removeHere].item);
2223    
2224        if (removeHere > 1) {
2225     /* previous argument gets this argument's post-indentation */
2226     free(line->elements[removeHere-1].indent);
2227     line->elements[removeHere-1].indent =
2228        line->elements[removeHere].indent;
2229        } else {
2230     free(line->elements[removeHere].indent);
2231        }
2232    
2233        /* now collapse the array, but don't bother to realloc smaller */
2234        for (i = removeHere; i < line->numElements - 1; i++)
2235     line->elements[i] = line->elements[i + 1];
2236    
2237        line->numElements--;
2238    }
2239    
2240  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2241      char * first, * second;      char * first, * second;
2242      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2259  int updateActualImage(struct grubConfig
2259      struct singleEntry * entry;      struct singleEntry * entry;
2260      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2261      int index = 0;      int index = 0;
2262      int i, j, k;      int i, k;
2263      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2264      const char ** arg;      const char ** arg;
2265      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2266      int firstElement;      int firstElement;
2267      int *usedElements, *usedArgs;      int *usedElements;
2268        int doreplace;
2269    
2270      if (!image) return 0;      if (!image) return 0;
2271    
# Line 1609  int updateActualImage(struct grubConfig Line 2292  int updateActualImage(struct grubConfig
2292   }   }
2293      }      }
2294    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2295    
2296      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2297   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2298    
2299      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2300   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2301    
2302      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2303    
2304      k = 0;   if (multibootArgs && !entry->multiboot)
2305      for (arg = newArgs; *arg; arg++)      continue;
2306          k++;  
2307      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2308     * LT_KERNELARGS, use that.  Otherwise use
2309     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2310     */
2311     if (useKernelArgs) {
2312        line = getLineByType(LT_KERNELARGS, entry->lines);
2313        if (!line) {
2314     /* no LT_KERNELARGS, need to add it */
2315     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2316           cfg->secondaryIndent, NULL);
2317        }
2318        firstElement = 1;
2319    
2320      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2321   index++;      line = getLineByType(LT_HYPER, entry->lines);
2322        if (!line) {
2323     /* a multiboot entry without LT_HYPER? */
2324     continue;
2325        }
2326        firstElement = 2;
2327    
2328   line = entry->lines;   } else {
2329   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2330   if (!line) continue;      if (!line) {
2331   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2332     continue;
2333          if (entry->multiboot && !multibootArgs) {      }
2334              /* 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;  
2335   }   }
2336    
2337   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2338      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2339      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2340     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2341        /* this is a multiboot entry, make sure there's
2342         * -- on the args line
2343         */
2344        for (i = firstElement; i < line->numElements; i++) {
2345     if (!strcmp(line->elements[i].item, "--"))
2346        break;
2347        }
2348        if (i == line->numElements) {
2349     /* assume all existing args are kernel args,
2350     * prepend -- to make it official
2351     */
2352     insertElement(line, "--", firstElement, cfg->cfi);
2353     i = firstElement;
2354        }
2355        if (!multibootArgs) {
2356     /* kernel args start after the -- */
2357     firstElement = i + 1;
2358        }
2359     } else if (cfg->cfi->mbConcatArgs) {
2360        /* this is a non-multiboot entry, remove hyper args */
2361        for (i = firstElement; i < line->numElements; i++) {
2362     if (!strcmp(line->elements[i].item, "--"))
2363        break;
2364        }
2365        if (i < line->numElements) {
2366     /* remove args up to -- */
2367     while (strcmp(line->elements[firstElement].item, "--"))
2368        removeElement(line, firstElement);
2369     /* remove -- */
2370     removeElement(line, firstElement);
2371        }
2372   }   }
2373    
2374          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2375    
2376          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2377   for (arg = newArgs; *arg; arg++) {  
2378              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2379      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2380     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2381        !strcmp(line->elements[i].item, "--"))
2382     {
2383        /* reached the end of hyper args, insert here */
2384        doreplace = 0;
2385        break;  
2386     }
2387                  if (usedElements[i])                  if (usedElements[i])
2388                      continue;                      continue;
2389   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2390                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2391      break;      break;
2392                  }                  }
2393              }              }
     chptr = strchr(*arg, '=');  
2394    
2395      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2396   /* replace */   /* direct replacement */
2397   free(line->elements[i].item);   free(line->elements[i].item);
2398   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("");  
  }  
2399    
2400   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2401   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2402      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2403   /* append */   if (rootLine) {
2404   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2405   (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(" ");  
2406   } else {   } else {
2407      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2408         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2409   }   }
2410        }
2411    
2412   line->numElements++;      else {
2413     /* insert/append */
2414     insertElement(line, *arg, i, cfg->cfi);
2415     usedElements = realloc(usedElements, line->numElements *
2416           sizeof(*usedElements));
2417     memmove(&usedElements[i + 1], &usedElements[i],
2418     line->numElements - i - 1);
2419     usedElements[i] = 1;
2420    
2421   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2422     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2423     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2424   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2425      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2426      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2427   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2428   }   }
2429      }      }
             k++;  
2430   }   }
2431    
2432          free(usedElements);          free(usedElements);
2433    
  /* 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? */  
2434   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2435      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2436   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2437        !strcmp(line->elements[i].item, "--"))
2438        /* reached the end of hyper args, stop here */
2439        break;
2440     if (!argMatch(line->elements[i].item, *arg)) {
2441        removeElement(line, i);
2442      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;  
2443   }   }
2444        }
2445   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2446        if (useRoot && !strncmp(*arg, "root=", 5)) {
2447   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2448      line->elements[j - 1] = line->elements[j];   if (rootLine)
2449        removeLine(entry, rootLine);
  line->numElements--;  
2450      }      }
2451   }   }
2452    
# Line 1760  int updateActualImage(struct grubConfig Line 2457  int updateActualImage(struct grubConfig
2457   }   }
2458      }      }
2459    
     free(usedArgs);  
2460      free(newArgs);      free(newArgs);
2461      free(oldArgs);      free(oldArgs);
2462    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2482  int updateImage(struct grubConfig * cfg,
2482      return rc;      return rc;
2483  }  }
2484    
2485    int updateInitrd(struct grubConfig * cfg, const char * image,
2486                     const char * prefix, const char * initrd) {
2487        struct singleEntry * entry;
2488        struct singleLine * line, * kernelLine, *endLine = NULL;
2489        int index = 0;
2490    
2491        if (!image) return 0;
2492    
2493        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2494            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2495            if (!kernelLine) continue;
2496    
2497            line = getLineByType(LT_INITRD, entry->lines);
2498            if (line)
2499                removeLine(entry, line);
2500            if (prefix) {
2501                int prefixLen = strlen(prefix);
2502                if (!strncmp(initrd, prefix, prefixLen))
2503                    initrd += prefixLen;
2504            }
2505     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2506     if (endLine)
2507        removeLine(entry, endLine);
2508            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2509            if (!line)
2510        return 1;
2511     if (endLine) {
2512        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2513                if (!line)
2514     return 1;
2515     }
2516    
2517            break;
2518        }
2519    
2520        return 0;
2521    }
2522    
2523  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2524      int fd;      int fd;
2525      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2543  int checkDeviceBootloader(const char * d
2543      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2544   return 0;   return 0;
2545    
2546      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2547   offset = boot[2] + 2;   offset = boot[2] + 2;
2548      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2549   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2550      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2551   offset = boot[1] + 2;        offset = boot[1] + 2;
2552            /*
2553     * it looks like grub, when copying stage1 into the mbr, patches stage1
2554     * right after the JMP location, replacing other instructions such as
2555     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2556     * different bytes.
2557     */
2558          if ((bootSect[offset + 1] == NOOP_OPCODE)
2559      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2560     offset = offset + 3;
2561          }
2562      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2563   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2564      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2700  int checkForLilo(struct grubConfig * con
2700      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2701  }  }
2702    
2703    int checkForGrub2(struct grubConfig * config) {
2704        if (!access("/etc/grub.d/", R_OK))
2705     return 2;
2706    
2707        return 1;
2708    }
2709    
2710  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2711      int fd;      int fd;
2712      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2727  int checkForGrub(struct grubConfig * con
2727      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2728   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2729   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2730     close(fd);
2731     return 1;
2732        }
2733        close(fd);
2734    
2735        return checkDeviceBootloader(boot, bootSect);
2736    }
2737    
2738    int checkForExtLinux(struct grubConfig * config) {
2739        int fd;
2740        unsigned char bootSect[512];
2741        char * boot;
2742        char executable[] = "/boot/extlinux/extlinux";
2743    
2744        printf("entered: checkForExtLinux()\n");
2745    
2746        if (parseSysconfigGrub(NULL, &boot))
2747     return 0;
2748    
2749        /* assume grub is not installed -- not an error condition */
2750        if (!boot)
2751     return 0;
2752    
2753        fd = open(executable, O_RDONLY);
2754        if (fd < 0)
2755     /* this doesn't exist if grub hasn't been installed */
2756     return 0;
2757    
2758        if (read(fd, bootSect, 512) != 512) {
2759     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2760     executable, strerror(errno));
2761   return 1;   return 1;
2762      }      }
2763      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2776  static char * getRootSpecifier(char * st
2776      return rootspec;      return rootspec;
2777  }  }
2778    
2779    static char * getInitrdVal(struct grubConfig * config,
2780       const char * prefix, struct singleLine *tmplLine,
2781       const char * newKernelInitrd,
2782       char ** extraInitrds, int extraInitrdCount)
2783    {
2784        char *initrdVal, *end;
2785        int i;
2786        size_t totalSize;
2787        size_t prefixLen;
2788        char separatorChar;
2789    
2790        prefixLen = strlen(prefix);
2791        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2792    
2793        for (i = 0; i < extraInitrdCount; i++) {
2794     totalSize += sizeof(separatorChar);
2795     totalSize += strlen(extraInitrds[i]) - prefixLen;
2796        }
2797    
2798        initrdVal = end = malloc(totalSize);
2799    
2800        end = stpcpy (end, newKernelInitrd + prefixLen);
2801    
2802        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2803        for (i = 0; i < extraInitrdCount; i++) {
2804     const char *extraInitrd;
2805     int j;
2806    
2807     extraInitrd = extraInitrds[i] + prefixLen;
2808     /* Don't add entries that are already there */
2809     if (tmplLine != NULL) {
2810        for (j = 2; j < tmplLine->numElements; j++)
2811     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2812        break;
2813    
2814        if (j != tmplLine->numElements)
2815     continue;
2816     }
2817    
2818     *end++ = separatorChar;
2819     end = stpcpy(end, extraInitrd);
2820        }
2821    
2822        return initrdVal;
2823    }
2824    
2825  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2826           const char * prefix,           const char * prefix,
2827   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2828   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2829     char ** extraInitrds, int extraInitrdCount,
2830                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2831      struct singleEntry * new;      struct singleEntry * new;
2832      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2833      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2834      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2835    
2836      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2837    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2861  int addNewKernel(struct grubConfig * con
2861      config->entries = new;      config->entries = new;
2862    
2863      /* copy/update from the template */      /* copy/update from the template */
2864      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2865        if (newKernelInitrd)
2866     needs |= NEED_INITRD;
2867      if (newMBKernel) {      if (newMBKernel) {
2868          needs |= KERNEL_MB;          needs |= NEED_MB;
2869          new->multiboot = 1;          new->multiboot = 1;
2870      }      }
2871    
2872      if (template) {      if (template) {
2873   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2874      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2875      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2876   indent = tmplLine->indent;   {
2877        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2878    
2879      /* skip comments */      /* skip comments */
2880      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2881      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2882      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2883    
2884      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2885      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2886     if (!template->multiboot && (needs & NEED_MB)) {
2887              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2888                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2889                  struct singleLine *l;       * hypervisor at the same time.
2890                  needs &= ~ KERNEL_MB;       */
2891        if (config->cfi->mbHyperFirst) {
2892                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2893                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2894                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2895                      newMBKernel + strlen(prefix));
2896                  tmplLine = lastLine;   /* set up for adding the kernel line */
2897                  if (!new->lines) {   free(tmplLine->indent);
2898                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2899                  } else {   needs &= ~NEED_MB;
2900                      newLine->next = l;      }
2901                      newLine = l;      if (needs & NEED_KERNEL) {
2902                  }   /* use addLineTmpl to preserve line elements,
2903                  continue;   * otherwise we could just call addLine.  Unfortunately
2904              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2905                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2906                  continue; /* don't need multiboot kernel here */   * change below.
2907              }   */
2908     struct keywordTypes * mbm_kw =
2909        getKeywordByType(LT_MBMODULE, config->cfi);
2910     if (mbm_kw) {
2911        tmplLine->type = LT_MBMODULE;
2912        free(tmplLine->elements[0].item);
2913        tmplLine->elements[0].item = strdup(mbm_kw->key);
2914     }
2915     newLine = addLineTmpl(new, tmplLine, newLine,
2916          newKernelPath + strlen(prefix), config->cfi);
2917     needs &= ~NEED_KERNEL;
2918        }
2919        if (needs & NEED_MB) { /* !mbHyperFirst */
2920     newLine = addLine(new, config->cfi, LT_HYPER,
2921      config->secondaryIndent,
2922      newMBKernel + strlen(prefix));
2923     needs &= ~NEED_MB;
2924        }
2925     } else if (needs & NEED_KERNEL) {
2926        newLine = addLineTmpl(new, tmplLine, newLine,
2927      newKernelPath + strlen(prefix), config->cfi);
2928        needs &= ~NEED_KERNEL;
2929     }
2930    
2931      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2932   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2933   new->lines = newLine;   if (needs & NEED_MB) {
2934      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2935   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2936   newLine = newLine->next;      needs &= ~NEED_MB;
2937      }   }
2938    
2939        } else if (tmplLine->type == LT_MBMODULE &&
2940           tmplLine->numElements >= 2) {
2941     if (new->multiboot) {
2942        if (needs & NEED_KERNEL) {
2943     newLine = addLineTmpl(new, tmplLine, newLine,
2944          newKernelPath +
2945          strlen(prefix), config->cfi);
2946     needs &= ~NEED_KERNEL;
2947        } else if (config->cfi->mbInitRdIsModule &&
2948           (needs & NEED_INITRD)) {
2949     char *initrdVal;
2950     initrdVal = getInitrdVal(config, prefix, tmplLine,
2951     newKernelInitrd, extraInitrds,
2952     extraInitrdCount);
2953     newLine = addLineTmpl(new, tmplLine, newLine,
2954          initrdVal, config->cfi);
2955     free(initrdVal);
2956     needs &= ~NEED_INITRD;
2957        }
2958     } else if (needs & NEED_KERNEL) {
2959        /* template is multi but new is not,
2960         * insert the kernel in the first module slot
2961         */
2962        tmplLine->type = LT_KERNEL;
2963        free(tmplLine->elements[0].item);
2964        tmplLine->elements[0].item =
2965     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2966        newLine = addLineTmpl(new, tmplLine, newLine,
2967      newKernelPath + strlen(prefix), config->cfi);
2968        needs &= ~NEED_KERNEL;
2969     } else if (needs & NEED_INITRD) {
2970        char *initrdVal;
2971        /* template is multi but new is not,
2972         * insert the initrd in the second module slot
2973         */
2974        tmplLine->type = LT_INITRD;
2975        free(tmplLine->elements[0].item);
2976        tmplLine->elements[0].item =
2977     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2978        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2979        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2980        free(initrdVal);
2981        needs &= ~NEED_INITRD;
2982     }
2983    
     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));  
                 }  
2984      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2985      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2986   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2987   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2988                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2989                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2990                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2991                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2992                  }       */
2993                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2994                  if (rootspec != NULL) {   char *initrdVal;
2995                      newLine->elements[1].item = sdupprintf("%s%s",  
2996                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2997                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2998                                                             strlen(prefix));    config->secondaryIndent,
2999                  } else {    initrdVal);
3000                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3001                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3002                  }      }
3003              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3004                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3005   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3006                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3007                      free(newLine->elements[0].item);      free(initrdVal);
3008                      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);  
3009   }   }
3010    
3011   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3012   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3013   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3014     char *nkt = malloc(strlen(newKernelTitle)+3);
3015     strcpy(nkt, "'");
3016     strcat(nkt, newKernelTitle);
3017     strcat(nkt, "'");
3018     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3019     free(nkt);
3020     needs &= ~NEED_TITLE;
3021      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3022                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3023                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3024                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3025                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3026                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3027                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3028                                             newLine->numElements);     config->cfi->titleBracketed) {
3029        /* addLineTmpl doesn't handle titleBracketed */
3030                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3031                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3032                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3033                  newLine->numElements = 1;   }
3034              }      } else if (tmplLine->type == LT_ECHO) {
3035        requote(tmplLine, config->cfi);
3036        static const char *prefix = "'Loading ";
3037        if (tmplLine->numElements > 1 &&
3038        strstr(tmplLine->elements[1].item, prefix) &&
3039        masterLine->next && masterLine->next->type == LT_KERNEL) {
3040     char *newTitle = malloc(strlen(prefix) +
3041     strlen(newKernelTitle) + 2);
3042    
3043     strcpy(newTitle, prefix);
3044     strcat(newTitle, newKernelTitle);
3045     strcat(newTitle, "'");
3046     newLine = addLine(new, config->cfi, LT_ECHO,
3047     tmplLine->indent, newTitle);
3048     free(newTitle);
3049        } else {
3050     /* pass through other lines from the template */
3051     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3052     config->cfi);
3053        }
3054        } else {
3055     /* pass through other lines from the template */
3056     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3057        }
3058   }   }
3059    
3060      } else {      } else {
3061   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3062      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3063     */
3064     switch (config->cfi->entryStart) {
3065        case LT_KERNEL:
3066     if (new->multiboot && config->cfi->mbHyperFirst) {
3067        /* fall through to LT_HYPER */
3068     } else {
3069        newLine = addLine(new, config->cfi, LT_KERNEL,
3070          config->primaryIndent,
3071          newKernelPath + strlen(prefix));
3072        needs &= ~NEED_KERNEL;
3073        break;
3074     }
3075    
3076        case LT_HYPER:
3077     newLine = addLine(new, config->cfi, LT_HYPER,
3078      config->primaryIndent,
3079      newMBKernel + strlen(prefix));
3080     needs &= ~NEED_MB;
3081   break;   break;
         }  
3082    
3083   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3084      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3085       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3086       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3087      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3088       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3089      default:        config->primaryIndent, nkt);
3090                  /* zipl strikes again */   free(nkt);
3091                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3092                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3093                      chptr = newKernelTitle;   break;
3094                      type = LT_TITLE;      }
3095                      break;      case LT_TITLE:
3096                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3097                      abort();   char * templabel;
3098                  }   int x = 0, y = 0;
3099   }  
3100     templabel = strdup(newKernelTitle);
3101     while( templabel[x]){
3102     if( templabel[x] == ' ' ){
3103     y = x;
3104     while( templabel[y] ){
3105     templabel[y] = templabel[y+1];
3106     y++;
3107     }
3108     }
3109     x++;
3110     }
3111     newLine = addLine(new, config->cfi, LT_TITLE,
3112      config->primaryIndent, templabel);
3113     free(templabel);
3114     }else{
3115     newLine = addLine(new, config->cfi, LT_TITLE,
3116      config->primaryIndent, newKernelTitle);
3117     }
3118     needs &= ~NEED_TITLE;
3119     break;
3120    
3121   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3122   new->lines = newLine;   abort();
3123     }
3124      }      }
3125    
3126      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3127          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3128              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3129                                config->secondaryIndent,       */
3130                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3131          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3132              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3133                                config->secondaryIndent,    newKernelTitle);
3134                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3135          /* don't need to check for title as it's guaranteed to have been      }
3136           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3137           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3138          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3139              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3140                                config->secondaryIndent,   needs &= ~NEED_MB;
3141                                newKernelInitrd + strlen(prefix));      }
3142      } else {      if (needs & NEED_KERNEL) {
3143          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3144              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3145                                config->secondaryIndent,        config->cfi)) ?
3146                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3147          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3148              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3149                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3150                                newKernelTitle);      }
3151          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3152              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3153                                config->secondaryIndent,    config->secondaryIndent,
3154                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3155     needs &= ~NEED_MB;
3156        }
3157        if (needs & NEED_INITRD) {
3158     char *initrdVal;
3159     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3160     newLine = addLine(new, config->cfi,
3161      (new->multiboot && getKeywordByType(LT_MBMODULE,
3162          config->cfi)) ?
3163      LT_MBMODULE : LT_INITRD,
3164      config->secondaryIndent,
3165      initrdVal);
3166     free(initrdVal);
3167     needs &= ~NEED_INITRD;
3168        }
3169        if (needs & NEED_END) {
3170     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3171     config->secondaryIndent, NULL);
3172     needs &= ~NEED_END;
3173        }
3174    
3175        if (needs) {
3176     printf(_("grubby: needs=%d, aborting\n"), needs);
3177     abort();
3178      }      }
3179    
3180      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3183  int addNewKernel(struct grubConfig * con
3183      return 0;      return 0;
3184  }  }
3185    
3186    static void traceback(int signum)
3187    {
3188        void *array[40];
3189        size_t size;
3190    
3191        signal(SIGSEGV, SIG_DFL);
3192        memset(array, '\0', sizeof (array));
3193        size = backtrace(array, 40);
3194    
3195        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3196                (unsigned long)size);
3197        backtrace_symbols_fd(array, size, STDERR_FILENO);
3198        exit(1);
3199    }
3200    
3201  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3202      poptContext optCon;      poptContext optCon;
3203      char * grubConfig = NULL;      const char * grubConfig = NULL;
3204      char * outputFile = NULL;      char * outputFile = NULL;
3205      int arg = 0;      int arg = 0;
3206      int flags = 0;      int flags = 0;
3207      int badImageOkay = 0;      int badImageOkay = 0;
3208        int configureGrub2 = 0;
3209      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3210      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3211        int configureExtLinux = 0;
3212      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3213        int extraInitrdCount = 0;
3214      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3215      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3216      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3226  int main(int argc, const char ** argv) {
3226      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3227      char * removeArgs = NULL;      char * removeArgs = NULL;
3228      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3229        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3230      const char * chptr = NULL;      const char * chptr = NULL;
3231      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3232      struct grubConfig * config;      struct grubConfig * config;
3233      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3234      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3235      int displayDefault = 0;      int displayDefault = 0;
3236        int displayDefaultIndex = 0;
3237        int displayDefaultTitle = 0;
3238      struct poptOption options[] = {      struct poptOption options[] = {
3239   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3240      _("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 3265  int main(int argc, const char ** argv) {
3265        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3266        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3267        "template"), NULL },        "template"), NULL },
3268     { "debug", 0, 0, &debug, 0,
3269        _("print debugging information for failures") },
3270   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3271      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3272     { "default-index", 0, 0, &displayDefaultIndex, 0,
3273        _("display the index of the default kernel") },
3274     { "default-title", 0, 0, &displayDefaultTitle, 0,
3275        _("display the title of the default kernel") },
3276   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3277      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3278     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3279        _("configure extlinux bootloader (from syslinux)") },
3280   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3281      _("configure grub bootloader") },      _("configure grub bootloader") },
3282     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3283        _("configure grub2 bootloader") },
3284   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3285      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3286      _("kernel-path") },      _("kernel-path") },
3287   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3288      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3289     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3290        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3291   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3292      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3293   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3324  int main(int argc, const char ** argv) {
3324   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3325      };      };
3326    
3327        useextlinuxmenu=0;
3328    
3329        signal(SIGSEGV, traceback);
3330    
3331      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3332      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3333    
# Line 2391  int main(int argc, const char ** argv) { Line 3337  int main(int argc, const char ** argv) {
3337      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3338      exit(0);      exit(0);
3339      break;      break;
3340      case 'i':
3341        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3342         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3343        } else {
3344     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3345     return 1;
3346        }
3347        break;
3348   }   }
3349      }      }
3350    
# Line 2406  int main(int argc, const char ** argv) { Line 3360  int main(int argc, const char ** argv) {
3360   return 1;   return 1;
3361      }      }
3362    
3363      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3364   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3365     configureExtLinux ) > 1) {
3366   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3367   return 1;   return 1;
3368      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3369   fprintf(stderr,   fprintf(stderr,
3370      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3371   return 1;   return 1;
3372        } else if (configureGrub2) {
3373     cfi = &grub2ConfigType;
3374      } else if (configureLilo) {      } else if (configureLilo) {
3375   cfi = &liloConfigType;   cfi = &liloConfigType;
3376      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3383  int main(int argc, const char ** argv) {
3383          cfi = &siloConfigType;          cfi = &siloConfigType;
3384      } else if (configureZipl) {      } else if (configureZipl) {
3385          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3386        } else if (configureExtLinux) {
3387     cfi = &extlinuxConfigType;
3388     useextlinuxmenu=1;
3389      }      }
3390    
3391      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3400  int main(int argc, const char ** argv) {
3400        #elif __s390x__        #elif __s390x__
3401          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3402        #else        #else
3403   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3404        cfi = &grub2ConfigType;
3405     else
3406        cfi = &grubConfigType;
3407        #endif        #endif
3408      }      }
3409    
3410      if (!grubConfig)      if (!grubConfig) {
3411   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3412        grubConfig = cfi->findConfig(cfi);
3413     if (!grubConfig)
3414        grubConfig = cfi->defaultConfig;
3415        }
3416    
3417      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3418    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3419    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3420   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3421    "specified option"));    "specified option"));
3422   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3432  int main(int argc, const char ** argv) {
3432      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3433   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3434   return 1;   return 1;
3435      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3436    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3437    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3438   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3439   return 1;   return 1;
3440      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3459  int main(int argc, const char ** argv) {
3459   defaultKernel = NULL;   defaultKernel = NULL;
3460      }      }
3461    
3462      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3463   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3464   "is used\n"));   "is used\n"));
3465   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3467  int main(int argc, const char ** argv) {
3467    
3468      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3469   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3470          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3471   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3472   return 1;   return 1;
3473      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3487  int main(int argc, const char ** argv) {
3487   bootPrefix = "";   bootPrefix = "";
3488      }      }
3489    
3490        if (!cfi->mbAllowExtraInitRds &&
3491     extraInitrdCount > 0) {
3492     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3493     return 1;
3494        }
3495    
3496      if (bootloaderProbe) {      if (bootloaderProbe) {
3497   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3498   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3499    
3500   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3501      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3502        gconfig = readConfig(grub2config, &grub2ConfigType);
3503        if (!gconfig)
3504     gr2c = 1;
3505        else
3506     gr2c = checkForGrub2(gconfig);
3507     }
3508    
3509     const char *grubconfig = grubFindConfig(&grubConfigType);
3510     if (!access(grubconfig, F_OK)) {
3511        gconfig = readConfig(grubconfig, &grubConfigType);
3512      if (!gconfig)      if (!gconfig)
3513   grc = 1;   grc = 1;
3514      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3523  int main(int argc, const char ** argv) {
3523   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3524   }   }
3525    
3526   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3527        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3528        if (!lconfig)
3529     erc = 1;
3530        else
3531     erc = checkForExtLinux(lconfig);
3532     }
3533    
3534     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3535    
3536   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3537     if (gr2c == 2) printf("grub2\n");
3538   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3539     if (erc == 2) printf("extlinux\n");
3540    
3541   return 0;   return 0;
3542      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3554  int main(int argc, const char ** argv) {
3554   if (!entry) return 0;   if (!entry) return 0;
3555   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3556    
3557   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3558   if (!line) return 0;   if (!line) return 0;
3559    
3560          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3562  int main(int argc, const char ** argv) {
3562                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3563    
3564   return 0;   return 0;
3565    
3566        } else if (displayDefaultTitle) {
3567     struct singleLine * line;
3568     struct singleEntry * entry;
3569    
3570     if (config->defaultImage == -1) return 0;
3571     entry = findEntryByIndex(config, config->defaultImage);
3572     if (!entry) return 0;
3573    
3574     if (!configureGrub2) {
3575      line = getLineByType(LT_TITLE, entry->lines);
3576      if (!line) return 0;
3577      printf("%s\n", line->elements[1].item);
3578    
3579     } else {
3580      int i;
3581      size_t len;
3582      char * start;
3583      char * tmp;
3584    
3585      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3586      line = getLineByType(LT_MENUENTRY, entry->lines);
3587      if (!line) return 0;
3588    
3589      for (i = 0; i < line->numElements; i++) {
3590    
3591        if (!strcmp(line->elements[i].item, "menuentry"))
3592          continue;
3593    
3594        if (*line->elements[i].item == '\'')
3595          start = line->elements[i].item + 1;
3596        else
3597          start = line->elements[i].item;
3598    
3599        len = strlen(start);
3600        if (*(start + len - 1) == '\'') {
3601          tmp = strdup(start);
3602          *(tmp + len - 1) = '\0';
3603          printf("%s", tmp);
3604          free(tmp);
3605          break;
3606        } else {
3607          printf("%s ", start);
3608        }
3609      }
3610      printf("\n");
3611     }
3612     return 0;
3613    
3614        } else if (displayDefaultIndex) {
3615            if (config->defaultImage == -1) return 0;
3616            printf("%i\n", config->defaultImage);
3617    
3618      } else if (kernelInfo)      } else if (kernelInfo)
3619   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3620    
# Line 2585  int main(int argc, const char ** argv) { Line 3630  int main(int argc, const char ** argv) {
3630      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3631      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3632                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3633        if (updateKernelPath && newKernelInitrd) {
3634                if (updateInitrd(config, updateKernelPath, bootPrefix,
3635                                 newKernelInitrd)) return 1;
3636        }
3637      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3638                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3639                         extraInitrds, extraInitrdCount,
3640                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3641            
3642    
# Line 2597  int main(int argc, const char ** argv) { Line 3647  int main(int argc, const char ** argv) {
3647      }      }
3648    
3649      if (!outputFile)      if (!outputFile)
3650   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3651    
3652      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3653  }  }

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