Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1748 by niro, Sat Feb 18 01:07:15 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
117    #define DEFAULT_SAVED_GRUB2 -3
118    
119  struct keywordTypes {  struct keywordTypes {
120      char * key;      char * key;
121      enum lineType_e type;      enum lineType_e type;
122      char nextChar;      char nextChar;
123  } ;      char separatorChar;
124    };
125    
126    struct configFileInfo;
127    
128    typedef const char *(*findConfigFunc)(struct configFileInfo *);
129    typedef const int (*writeLineFunc)(struct configFileInfo *,
130     struct singleLine *line);
131    
132  struct configFileInfo {  struct configFileInfo {
133      char * defaultConfig;      char * defaultConfig;
134        findConfigFunc findConfig;
135        writeLineFunc writeLine;
136      struct keywordTypes * keywords;      struct keywordTypes * keywords;
137      int defaultIsIndex;      int defaultIsIndex;
138        int defaultIsVariable;
139      int defaultSupportSaved;      int defaultSupportSaved;
140      enum lineType_e entrySeparator;      enum lineType_e entryStart;
141        enum lineType_e entryEnd;
142      int needsBootPrefix;      int needsBootPrefix;
143      int argsInQuotes;      int argsInQuotes;
144      int maxTitleLength;      int maxTitleLength;
145      int titleBracketed;      int titleBracketed;
146        int titlePosition;
147        int mbHyperFirst;
148        int mbInitRdIsModule;
149        int mbConcatArgs;
150        int mbAllowExtraInitRds;
151  };  };
152    
153  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 156  struct keywordTypes grubKeywords[] = {
156      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
157      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
158      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
159      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
160      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
161        { "kernel",     LT_HYPER,       ' ' },
162      { NULL,    0, 0 },      { NULL,    0, 0 },
163  };  };
164    
165    const char *grubFindConfig(struct configFileInfo *cfi) {
166        static const char *configFiles[] = {
167     "/etc/grub.conf",
168     "/boot/grub/grub.conf",
169     "/boot/grub/menu.lst",
170     NULL
171        };
172        static int i = -1;
173    
174        if (i == -1) {
175     for (i = 0; configFiles[i] != NULL; i++) {
176        dbgPrintf("Checking \"%s\": ", configFiles[i]);
177        if (!access(configFiles[i], R_OK)) {
178     dbgPrintf("found\n");
179     return configFiles[i];
180        }
181        dbgPrintf("not found\n");
182     }
183        }
184        return configFiles[i];
185    }
186    
187  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
188      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
189      grubKeywords,    /* keywords */      .keywords = grubKeywords,
190      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
191      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
192      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
193      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
194      0,    /* argsInQuotes */      .mbHyperFirst = 1,
195      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
196      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
197    };
198    
199    struct keywordTypes grub2Keywords[] = {
200        { "menuentry",  LT_MENUENTRY,   ' ' },
201        { "}",          LT_ENTRY_END,   ' ' },
202        { "echo",       LT_ECHO,        ' ' },
203        { "set",        LT_SET_VARIABLE,' ', '=' },
204        { "root",       LT_BOOTROOT,    ' ' },
205        { "default",    LT_DEFAULT,     ' ' },
206        { "fallback",   LT_FALLBACK,    ' ' },
207        { "linux",      LT_KERNEL,      ' ' },
208        { "initrd",     LT_INITRD,      ' ', ' ' },
209        { "module",     LT_MBMODULE,    ' ' },
210        { "kernel",     LT_HYPER,       ' ' },
211        { NULL, 0, 0 },
212    };
213    
214    const char *grub2FindConfig(struct configFileInfo *cfi) {
215        static const char *configFiles[] = {
216     "/boot/grub/grub-efi.cfg",
217     "/boot/grub/grub.cfg",
218     NULL
219        };
220        static int i = -1;
221        static const char *grub_cfg = "/boot/grub/grub.cfg";
222    
223        if (i == -1) {
224     for (i = 0; configFiles[i] != NULL; i++) {
225        dbgPrintf("Checking \"%s\": ", configFiles[i]);
226        if (!access(configFiles[i], R_OK)) {
227     dbgPrintf("found\n");
228     return configFiles[i];
229        }
230     }
231        }
232    
233        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
234         * that isn't in grub1, and if it exists, return the config file path
235         * that they use. */
236        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
237     dbgPrintf("found\n");
238     return grub_cfg;
239        }
240    
241        dbgPrintf("not found\n");
242        return configFiles[i];
243    }
244    
245    int sizeOfSingleLine(struct singleLine * line) {
246      int i;
247      int count = 0;
248    
249      for (i = 0; i < line->numElements; i++) {
250        int indentSize = 0;
251    
252        count = count + strlen(line->elements[i].item);
253    
254        indentSize = strlen(line->elements[i].indent);
255        if (indentSize > 0)
256          count = count + indentSize;
257        else
258          /* be extra safe and add room for whitespaces */
259          count = count + 1;
260      }
261    
262      /* room for trailing terminator */
263      count = count + 1;
264    
265      return count;
266    }
267    
268    char *grub2ExtractTitle(struct singleLine * line) {
269        char * current;
270        char * current_indent;
271        int current_len;
272        int current_indent_len;
273        int i;
274    
275        /* bail out if line does not start with menuentry */
276        if (strcmp(line->elements[0].item, "menuentry"))
277          return NULL;
278    
279        i = 1;
280        current = line->elements[i].item;
281        current_len = strlen(current);
282    
283        /* if second word is quoted, strip the quotes and return single word */
284        if ((*current == '\'') && (*(current + current_len - 1) == '\'')) {
285          char *tmp;
286    
287          tmp = strdup(current);
288          *(tmp + current_len - 1) = '\0';
289          return ++tmp;
290        }
291    
292        /* if no quotes, return second word verbatim */
293        if (*current != '\'') {
294          return current;
295        }
296    
297        /* second element start with a quote, so we have to find the element
298         * whose last character is also quote (assuming it's the closing one) */
299        if (*current == '\'') {
300          int resultMaxSize;
301          char * result;
302    
303          resultMaxSize = sizeOfSingleLine(line);
304          result = malloc(resultMaxSize);
305          snprintf(result, resultMaxSize, "%s", ++current);
306    
307          i++;
308          for (; i < line->numElements; ++i) {
309     current = line->elements[i].item;
310     current_len = strlen(current);
311     current_indent = line->elements[i].indent;
312     current_indent_len = strlen(current_indent);
313    
314     strncat(result, current_indent, current_indent_len);
315     if (*(current + current_len - 1) != '\'') {
316      strncat(result, current, current_len);
317     } else {
318      strncat(result, current, current_len - 1);
319      break;
320     }
321          }
322          return result;
323        }
324    
325        return NULL;
326    }
327    
328    struct configFileInfo grub2ConfigType = {
329        .findConfig = grub2FindConfig,
330        .keywords = grub2Keywords,
331        .defaultIsIndex = 1,
332        .defaultSupportSaved = 1,
333        .defaultIsVariable = 1,
334        .entryStart = LT_MENUENTRY,
335        .entryEnd = LT_ENTRY_END,
336        .titlePosition = 1,
337        .needsBootPrefix = 1,
338        .mbHyperFirst = 1,
339        .mbInitRdIsModule = 1,
340        .mbAllowExtraInitRds = 1,
341  };  };
342    
343  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 371  struct keywordTypes yabootKeywords[] = {
371      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
372      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
373      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
374      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
375      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
376      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
377      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 391  struct keywordTypes liloKeywords[] = {
391      { NULL,    0, 0 },      { NULL,    0, 0 },
392  };  };
393    
394    struct keywordTypes eliloKeywords[] = {
395        { "label",    LT_TITLE,    '=' },
396        { "root",    LT_ROOT,    '=' },
397        { "default",    LT_DEFAULT,    '=' },
398        { "image",    LT_KERNEL,    '=' },
399        { "initrd",    LT_INITRD,    '=' },
400        { "append",    LT_KERNELARGS,  '=' },
401        { "vmm",    LT_HYPER,       '=' },
402        { NULL,    0, 0 },
403    };
404    
405  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
406      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
407      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 423  struct keywordTypes ziplKeywords[] = {
423      { NULL,         0, 0 },      { NULL,         0, 0 },
424  };  };
425    
426    struct keywordTypes extlinuxKeywords[] = {
427        { "label",    LT_TITLE,    ' ' },
428        { "root",    LT_ROOT,    ' ' },
429        { "default",    LT_DEFAULT,    ' ' },
430        { "kernel",    LT_KERNEL,    ' ' },
431        { "initrd",    LT_INITRD,      ' ', ',' },
432        { "append",    LT_KERNELARGS,  ' ' },
433        { "prompt",     LT_UNKNOWN,     ' ' },
434        { NULL,    0, 0 },
435    };
436    int useextlinuxmenu;
437  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
438      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
439      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
440      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
441      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
442      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
443      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
444  };  };
445    
446  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
447      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
448      liloKeywords,    /* keywords */      .keywords = liloKeywords,
449      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
450      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
451      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
452  };  };
453    
454  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
455      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
456      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
457      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
458      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
459      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
460      1,    /* needsBootPrefix */      .maxTitleLength = 15,
461      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
462  };  };
463    
464  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
465      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
466      siloKeywords,    /* keywords */      .keywords = siloKeywords,
467      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
468      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
469      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
470      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
471  };  };
472    
473  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
474      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
475      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
476      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
477      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
478      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
479      0,    /* needsBootPrefix */  };
480      1,    /* argsInQuotes */  
481      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
482      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
483        .keywords = extlinuxKeywords,
484        .entryStart = LT_TITLE,
485        .needsBootPrefix = 1,
486        .maxTitleLength = 255,
487        .mbAllowExtraInitRds = 1,
488  };  };
489    
490  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 499  struct grubConfig {
499      struct configFileInfo * cfi;      struct configFileInfo * cfi;
500  };  };
501    
502    blkid_cache blkid;
503    
504  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
505  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
506       const char * path, const char * prefix,       const char * path, const char * prefix,
507       int * index);       int * index);
 static char * strndup(char * from, int len);  
508  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
509  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
510    struct singleLine * lineDup(struct singleLine * line);
511  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
512  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
513       struct configFileInfo * cfi);       struct configFileInfo * cfi);
514  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
515         struct configFileInfo * cfi);         struct configFileInfo * cfi);
516  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
517    static void requote(struct singleLine *line, struct configFileInfo * cfi);
518  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
519      char * to;    const char * item, int insertHere,
520      struct configFileInfo * cfi);
521      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
522      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
523      to[len] = '\0';        struct configFileInfo * cfi);
524    static enum lineType_e getTypeByKeyword(char * keyword,
525      return to;   struct configFileInfo * cfi);
526  }  static struct singleLine * getLineByType(enum lineType_e type,
527     struct singleLine * line);
528    static int checkForExtLinux(struct grubConfig * config);
529    struct singleLine * addLineTmpl(struct singleEntry * entry,
530                                    struct singleLine * tmplLine,
531                                    struct singleLine * prevLine,
532                                    const char * val,
533     struct configFileInfo * cfi);
534    struct singleLine *  addLine(struct singleEntry * entry,
535                                 struct configFileInfo * cfi,
536                                 enum lineType_e type, char * defaultIndent,
537                                 const char * val);
538    
539  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
540  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 569  static char * sdupprintf(const char *for
569      return buf;      return buf;
570  }  }
571    
572    static struct keywordTypes * getKeywordByType(enum lineType_e type,
573          struct configFileInfo * cfi) {
574        struct keywordTypes * kw;
575        for (kw = cfi->keywords; kw->key; kw++) {
576     if (kw->type == type)
577        return kw;
578        }
579        return NULL;
580    }
581    
582    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
583        struct keywordTypes *kt = getKeywordByType(type, cfi);
584        if (kt)
585     return kt->key;
586        return "unknown";
587    }
588    
589    static char * getpathbyspec(char *device) {
590        if (!blkid)
591            blkid_get_cache(&blkid, NULL);
592    
593        return blkid_get_devname(blkid, device, NULL);
594    }
595    
596    static char * getuuidbydev(char *device) {
597        if (!blkid)
598     blkid_get_cache(&blkid, NULL);
599    
600        return blkid_get_tag_value(blkid, "UUID", device);
601    }
602    
603    static enum lineType_e getTypeByKeyword(char * keyword,
604     struct configFileInfo * cfi) {
605        struct keywordTypes * kw;
606        for (kw = cfi->keywords; kw->key; kw++) {
607     if (!strcmp(keyword, kw->key))
608        return kw->type;
609        }
610        return LT_UNKNOWN;
611    }
612    
613    static struct singleLine * getLineByType(enum lineType_e type,
614     struct singleLine * line) {
615        dbgPrintf("getLineByType(%d): ", type);
616        for (; line; line = line->next) {
617     dbgPrintf("%d:%s ", line->type,
618      line->numElements ? line->elements[0].item : "(empty)");
619     if (line->type & type) break;
620        }
621        dbgPrintf(line ? "\n" : " (failed)\n");
622        return line;
623    }
624    
625  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
626      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
627          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
628          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
629              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 635  static int isBracketedTitle(struct singl
635      return 0;      return 0;
636  }  }
637    
638  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
639                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
640      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
641   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;  
642  }  }
643    
644  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 689  static void lineInit(struct singleLine *
689      line->next = NULL;      line->next = NULL;
690  }  }
691    
692    struct singleLine * lineDup(struct singleLine * line) {
693        int i;
694        struct singleLine * newLine = malloc(sizeof(*newLine));
695    
696        newLine->indent = strdup(line->indent);
697        newLine->next = NULL;
698        newLine->type = line->type;
699        newLine->numElements = line->numElements;
700        newLine->elements = malloc(sizeof(*newLine->elements) *
701           newLine->numElements);
702    
703        for (i = 0; i < newLine->numElements; i++) {
704     newLine->elements[i].indent = strdup(line->elements[i].indent);
705     newLine->elements[i].item = strdup(line->elements[i].item);
706        }
707    
708        return newLine;
709    }
710    
711  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
712      int i;      int i;
713    
# Line 414  static int lineWrite(FILE * out, struct Line 733  static int lineWrite(FILE * out, struct
733      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
734    
735   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
736   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
737        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
738      }      }
739    
740      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 753  static int getNextLine(char ** bufPtr, s
753      char * chptr;      char * chptr;
754      int elementsAlloced = 0;      int elementsAlloced = 0;
755      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
756      int first = 1;      int first = 1;
     int i;  
757    
758      lineFree(line);      lineFree(line);
759    
# Line 489  static int getNextLine(char ** bufPtr, s Line 807  static int getNextLine(char ** bufPtr, s
807      if (!line->numElements)      if (!line->numElements)
808   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
809      else {      else {
810   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
811      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;  
               
812              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
813               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
814              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 844  static int getNextLine(char ** bufPtr, s
844   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
845   line->numElements = 0;   line->numElements = 0;
846      }      }
847     } else {
848     struct keywordTypes *kw;
849    
850     kw = getKeywordByType(line->type, cfi);
851    
852     /* space isn't the only separator, we need to split
853     * elements up more
854     */
855     if (!isspace(kw->separatorChar)) {
856        int i;
857        char indent[2] = "";
858        indent[0] = kw->separatorChar;
859        for (i = 1; i < line->numElements; i++) {
860     char *p;
861     int j;
862     int numNewElements;
863    
864     numNewElements = 0;
865     p = line->elements[i].item;
866     while (*p != '\0') {
867     if (*p == kw->separatorChar)
868     numNewElements++;
869     p++;
870     }
871     if (line->numElements + numNewElements >= elementsAlloced) {
872     elementsAlloced += numNewElements + 5;
873     line->elements = realloc(line->elements,
874        sizeof(*line->elements) * elementsAlloced);
875     }
876    
877     for (j = line->numElements; j > i; j--) {
878     line->elements[j + numNewElements] = line->elements[j];
879     }
880     line->numElements += numNewElements;
881    
882     p = line->elements[i].item;
883     while (*p != '\0') {
884    
885     while (*p != kw->separatorChar && *p != '\0') p++;
886     if (*p == '\0') {
887     break;
888     }
889    
890     free(line->elements[i].indent);
891     line->elements[i].indent = strdup(indent);
892     *p++ = '\0';
893     i++;
894     line->elements[i].item = strdup(p);
895     line->elements[i].indent = strdup("");
896     p = line->elements[i].item;
897     }
898        }
899     }
900   }   }
901      }      }
902    
# Line 595  static struct grubConfig * readConfig(co Line 960  static struct grubConfig * readConfig(co
960      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
961   }   }
962    
963   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
964      sawEntry = 1;      sawEntry = 1;
965      if (!entry) {      if (!entry) {
966   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 976  static struct grubConfig * readConfig(co
976      entry->next = NULL;      entry->next = NULL;
977   }   }
978    
979   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
980        int i;
981        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
982        dbgPrintf("%s", line->indent);
983        for (i = 0; i < line->numElements; i++)
984     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
985        dbgPrintf("\n");
986        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
987        if (kwType && line->numElements == 3 &&
988        !strcmp(line->elements[1].item, kwType->key)) {
989     dbgPrintf("Line sets default config\n");
990     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
991     defaultLine = line;
992        }
993     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
994      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
995      defaultLine = line;      defaultLine = line;
996    
997            } else if (line->type == LT_KERNEL) {
998        /* if by some freak chance this is multiboot and the "module"
999         * lines came earlier in the template, make sure to use LT_HYPER
1000         * instead of LT_KERNEL now
1001         */
1002        if (entry->multiboot)
1003     line->type = LT_HYPER;
1004    
1005          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1006        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1007         * instead, now that we know this is a multiboot entry.
1008         * This only applies to grub, but that's the only place we
1009         * should find LT_MBMODULE lines anyway.
1010         */
1011        struct singleLine * l;
1012        for (l = entry->lines; l; l = l->next) {
1013     if (l->type == LT_HYPER)
1014        break;
1015     else if (l->type == LT_KERNEL) {
1016        l->type = LT_HYPER;
1017        break;
1018     }
1019        }
1020              entry->multiboot = 1;              entry->multiboot = 1;
1021    
1022     } else if (line->type == LT_HYPER) {
1023        entry->multiboot = 1;
1024    
1025   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1026      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1027      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1028    
1029   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1030      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1031      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 1050  static struct grubConfig * readConfig(co
1050      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1051      line->elements[1].item = buf;      line->elements[1].item = buf;
1052      line->numElements = 2;      line->numElements = 2;
1053    
1054   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1055      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1056         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 1060  static struct grubConfig * readConfig(co
1060   int last, len;   int last, len;
1061    
1062   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
1063      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1064     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1065    
1066   last = line->numElements - 1;   last = line->numElements - 1;
1067   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1068   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
1069      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1070      }      }
   
1071   }   }
1072    
1073   /* 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 1087  static struct grubConfig * readConfig(co
1087   movedLine = 1;   movedLine = 1;
1088   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1089   }   }
1090    
1091   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1092     which was moved, drop it. */     which was moved, drop it. */
1093   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 1103  static struct grubConfig * readConfig(co
1103   entry->lines = line;   entry->lines = line;
1104      else      else
1105   last->next = line;   last->next = line;
1106        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1107    
1108        /* we could have seen this outside of an entry... if so, we
1109         * ignore it like any other line we don't grok */
1110        if (line->type == LT_ENTRY_END && sawEntry)
1111     sawEntry = 0;
1112   } else {   } else {
1113      if (!cfg->theLines)      if (!cfg->theLines)
1114   cfg->theLines = line;   cfg->theLines = line;
1115      else {      else
1116   last->next = line;   last->next = line;
1117      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1118   }   }
1119    
1120   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1122  static struct grubConfig * readConfig(co
1122    
1123      free(incoming);      free(incoming);
1124    
1125        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1126      if (defaultLine) {      if (defaultLine) {
1127   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1128        cfi->defaultSupportSaved &&
1129        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1130        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1131     } else if (cfi->defaultIsVariable) {
1132        char *value = defaultLine->elements[2].item;
1133        while (*value && (*value == '"' || *value == '\'' ||
1134        *value == ' ' || *value == '\t'))
1135     value++;
1136        cfg->defaultImage = strtol(value, &end, 10);
1137        while (*end && (*end == '"' || *end == '\'' ||
1138        *end == ' ' || *end == '\t'))
1139     end++;
1140        if (*end) cfg->defaultImage = -1;
1141     } else if (cfi->defaultSupportSaved &&
1142   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1143      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1144   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1159  static struct grubConfig * readConfig(co
1159                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1160                  }                  }
1161   i++;   i++;
1162     entry = NULL;
1163      }      }
1164    
1165      if (entry) cfg->defaultImage = i;      if (entry){
1166            cfg->defaultImage = i;
1167        }else{
1168            cfg->defaultImage = -1;
1169        }
1170   }   }
1171        } else {
1172            cfg->defaultImage = 0;
1173      }      }
1174    
1175      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1185  static void writeDefault(FILE * out, cha
1185    
1186      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1187   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1188        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1189     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1190      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1191   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1192      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1193      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1194     cfg->defaultImage);
1195        } else {
1196     fprintf(out, "%sdefault%s%d\n", indent, separator,
1197     cfg->defaultImage);
1198        }
1199   } else {   } else {
1200      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1201    
# Line 769  static void writeDefault(FILE * out, cha Line 1212  static void writeDefault(FILE * out, cha
1212    
1213      if (!entry) return;      if (!entry) return;
1214    
1215      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1216    
1217      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1218   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1246  static int writeConfig(struct grubConfig
1246      int rc;      int rc;
1247    
1248      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1249         directory to / */         directory to the dir of the symlink */
1250      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1251      do {      do {
1252   buf = alloca(len + 1);   buf = alloca(len + 1);
1253   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1254   if (rc == len) len += 256;   if (rc == len) len += 256;
1255      } while (rc == len);      } while (rc == len);
1256            
# Line 843  static int writeConfig(struct grubConfig Line 1285  static int writeConfig(struct grubConfig
1285      }      }
1286    
1287      line = cfg->theLines;      line = cfg->theLines;
1288        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1289      while (line) {      while (line) {
1290   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1291     line->numElements == 3 &&
1292     !strcmp(line->elements[1].item, defaultKw->key)) {
1293        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1294        needs &= ~MAIN_DEFAULT;
1295     } else if (line->type == LT_DEFAULT) {
1296      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1297      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1298   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1360  static int numEntries(struct grubConfig
1360      return i;      return i;
1361  }  }
1362    
1363    static char *findDiskForRoot()
1364    {
1365        int fd;
1366        char buf[65536];
1367        char *devname;
1368        char *chptr;
1369        int rc;
1370    
1371        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1372            fprintf(stderr, "grubby: failed to open %s: %s\n",
1373                    _PATH_MOUNTED, strerror(errno));
1374            return NULL;
1375        }
1376    
1377        rc = read(fd, buf, sizeof(buf) - 1);
1378        if (rc <= 0) {
1379            fprintf(stderr, "grubby: failed to read %s: %s\n",
1380                    _PATH_MOUNTED, strerror(errno));
1381            close(fd);
1382            return NULL;
1383        }
1384        close(fd);
1385        buf[rc] = '\0';
1386        chptr = buf;
1387    
1388        while (chptr && chptr != buf+rc) {
1389            devname = chptr;
1390    
1391            /*
1392             * The first column of a mtab entry is the device, but if the entry is a
1393             * special device it won't start with /, so move on to the next line.
1394             */
1395            if (*devname != '/') {
1396                chptr = strchr(chptr, '\n');
1397                if (chptr)
1398                    chptr++;
1399                continue;
1400            }
1401    
1402            /* Seek to the next space */
1403            chptr = strchr(chptr, ' ');
1404            if (!chptr) {
1405                fprintf(stderr, "grubby: error parsing %s: %s\n",
1406                        _PATH_MOUNTED, strerror(errno));
1407                return NULL;
1408            }
1409    
1410            /*
1411             * The second column of a mtab entry is the mount point, we are looking
1412             * for '/' obviously.
1413             */
1414            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1415                /*
1416                 * Move back 2, which is the first space after the device name, set
1417                 * it to \0 so strdup will just get the devicename.
1418                 */
1419                chptr -= 2;
1420                *chptr = '\0';
1421                return strdup(devname);
1422            }
1423    
1424            /* Next line */
1425            chptr = strchr(chptr, '\n');
1426            if (chptr)
1427                chptr++;
1428        }
1429    
1430        return NULL;
1431    }
1432    
1433    void printEntry(struct singleEntry * entry) {
1434        int i;
1435        struct singleLine * line;
1436    
1437        for (line = entry->lines; line; line = line->next) {
1438     fprintf(stderr, "DBG: %s", line->indent);
1439     for (i = 0; i < line->numElements; i++) {
1440     fprintf(stderr, "%s%s",
1441        line->elements[i].item, line->elements[i].indent);
1442     }
1443     fprintf(stderr, "\n");
1444        }
1445    }
1446    
1447    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1448    {
1449        va_list argp;
1450    
1451        if (!debug)
1452     return;
1453    
1454        va_start(argp, fmt);
1455        fprintf(stderr, "DBG: Image entry failed: ");
1456        vfprintf(stderr, fmt, argp);
1457        printEntry(entry);
1458        va_end(argp);
1459    }
1460    
1461    #define beginswith(s, c) ((s) && (s)[0] == (c))
1462    
1463    static int endswith(const char *s, char c)
1464    {
1465     int slen;
1466    
1467     if (!s && !s[0])
1468     return 0;
1469     slen = strlen(s) - 1;
1470    
1471     return s[slen] == c;
1472    }
1473    
1474  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1475    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1476      struct singleLine * line;      struct singleLine * line;
1477      char * fullName;      char * fullName;
1478      int i;      int i;
     struct stat sb, sb2;  
1479      char * dev;      char * dev;
     char * end;  
1480      char * rootspec;      char * rootspec;
1481        char * rootdev;
1482    
1483      line = entry->lines;      if (skipRemoved && entry->skip) {
1484      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1485         return 0;
1486      if (!line) return 0;      }
1487      if (skipRemoved && entry->skip) return 0;  
1488      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1489        if (!line) {
1490     notSuitablePrintf(entry, "no line found\n");
1491     return 0;
1492        }
1493        if (line->numElements < 2) {
1494     notSuitablePrintf(entry, "line has only %d elements\n",
1495        line->numElements);
1496     return 0;
1497        }
1498    
1499      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1500    
1501      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1502        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1503      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1504      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1505              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1506                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1507      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1508                line->elements[1].item + rootspec_offset);
1509        if (access(fullName, R_OK)) {
1510     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1511     return 0;
1512        }
1513      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1514   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1515      if (i < line->numElements) {      if (i < line->numElements) {
1516   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1517      } else {      } else {
1518   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1519   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1520    
1521   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1522      dev = line->elements[1].item;      dev = line->elements[1].item;
1523   } else {   } else {
1524              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1525      /* 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.
1526      line = entry->lines;       */
1527        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1528    
1529              /* failed to find one */              /* failed to find one */
1530              if (!line) return 0;              if (!line) {
1531     notSuitablePrintf(entry, "no line found\n");
1532     return 0;
1533                }
1534    
1535      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1536          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1537      if (i < line->numElements)      if (i < line->numElements)
1538          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1539      else {      else {
1540     notSuitablePrintf(entry, "no root= entry found\n");
1541   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1542          return 0;          return 0;
1543              }              }
1544   }   }
1545      }      }
1546    
1547      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1548   dev += 6;      if (!getpathbyspec(dev)) {
1549            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1550   /* check which device has this label */          return 0;
1551   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1552   if (!dev) return 0;   dev = getpathbyspec(dev);
1553    
1554        rootdev = findDiskForRoot();
1555        if (!rootdev) {
1556            notSuitablePrintf(entry, "can't find root device\n");
1557     return 0;
1558      }      }
1559    
1560      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1561   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1562      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1563      } else {          free(rootdev);
1564   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1565   if (*end) return 0;      }
1566    
1567        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1568            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1569     getuuidbydev(rootdev), getuuidbydev(dev));
1570     free(rootdev);
1571            return 0;
1572      }      }
     stat("/", &sb2);  
1573    
1574      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1575    
1576      return 1;      return 1;
1577  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1615  struct singleEntry * findEntryByPath(str
1615   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1616   if (!entry) return NULL;   if (!entry) return NULL;
1617    
1618   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1619   if (!line) return NULL;   if (!line) return NULL;
1620    
1621   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1657  struct singleEntry * findEntryByPath(str
1657      kernel += 6;      kernel += 6;
1658   }   }
1659    
1660   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1661      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1662    
1663        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1664    
1665      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1666                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1667          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1668                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1669                              kernel + strlen(prefix)))       checkType, line);
1670                      break;   if (!line) break;  /* not found in this entry */
1671              }  
1672                 if (line && line->numElements >= 2) {
1673              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1674              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1675                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1676                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1677                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1678                      if (!strcmp(line->elements[1].item  +   }
1679                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1680    
1681      i++;      /* make sure this entry has a kernel identifier; this skips
1682         * non-Linux boot entries (could find netbsd etc, though, which is
1683         * unfortunate)
1684         */
1685        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1686     break; /* found 'im! */
1687   }   }
1688    
1689   if (index) *index = i;   if (index) *index = i;
1690      }      }
1691    
     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);  
     }  
   
1692      return entry;      return entry;
1693  }  }
1694    
# Line 1227  void setDefaultImage(struct grubConfig * Line 1794  void setDefaultImage(struct grubConfig *
1794    
1795      /* defaultImage now points to what we'd like to use, but before any order      /* defaultImage now points to what we'd like to use, but before any order
1796         changes */         changes */
1797      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1798     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1799        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1800        return;        return;
1801    
# Line 1286  void displayEntry(struct singleEntry * e Line 1854  void displayEntry(struct singleEntry * e
1854      char * root = NULL;      char * root = NULL;
1855      int i;      int i;
1856    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1857      printf("index=%d\n", index);      printf("index=%d\n", index);
1858    
1859      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1860        if (!line) {
1861            printf("non linux entry\n");
1862            return;
1863        }
1864    
1865        printf("kernel=%s%s\n", prefix, line->elements[1].item);
1866    
1867      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1868   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1879  void displayEntry(struct singleEntry * e
1879   }   }
1880   printf("\"\n");   printf("\"\n");
1881      } else {      } else {
1882   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1883   if (line) {   if (line) {
1884      char * s;      char * s;
1885    
# Line 1334  void displayEntry(struct singleEntry * e Line 1903  void displayEntry(struct singleEntry * e
1903      }      }
1904    
1905      if (!root) {      if (!root) {
1906   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1907   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1908      root=line->elements[1].item;      root=line->elements[1].item;
1909      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1918  void displayEntry(struct singleEntry * e
1918   printf("root=%s\n", s);   printf("root=%s\n", s);
1919      }      }
1920    
1921      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1922    
1923      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1924   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1935  int parseSysconfigGrub(int * lbaPtr, cha
1935      char * start;      char * start;
1936      char * param;      char * param;
1937    
1938      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1939      if (!in) return 1;      if (!in) return 1;
1940    
1941      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1997  int displayInfo(struct grubConfig * conf
1997   return 1;   return 1;
1998      }      }
1999    
2000      /* 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
2001         be a better way */         be a better way */
2002      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2003   dumpSysconfigGrub();   dumpSysconfigGrub();
2004      } else {      } else {
2005   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2006   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2007      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2008   }   }
2009    
2010   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2011   if (line) printf("lba\n");   if (line) printf("lba\n");
2012      }      }
2013    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2022  int displayInfo(struct grubConfig * conf
2022      return 0;      return 0;
2023  }  }
2024    
2025    struct singleLine * addLineTmpl(struct singleEntry * entry,
2026     struct singleLine * tmplLine,
2027     struct singleLine * prevLine,
2028     const char * val,
2029     struct configFileInfo * cfi)
2030    {
2031        struct singleLine * newLine = lineDup(tmplLine);
2032    
2033        if (val) {
2034     /* override the inherited value with our own.
2035     * This is a little weak because it only applies to elements[1]
2036     */
2037     if (newLine->numElements > 1)
2038        removeElement(newLine, 1);
2039     insertElement(newLine, val, 1, cfi);
2040    
2041     /* but try to keep the rootspec from the template... sigh */
2042     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2043        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2044        if (rootspec != NULL) {
2045     free(newLine->elements[1].item);
2046     newLine->elements[1].item =
2047        sdupprintf("%s%s", rootspec, val);
2048        }
2049     }
2050        }
2051    
2052        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2053          newLine->elements[0].item : "");
2054    
2055        if (!entry->lines) {
2056     /* first one on the list */
2057     entry->lines = newLine;
2058        } else if (prevLine) {
2059     /* add after prevLine */
2060     newLine->next = prevLine->next;
2061     prevLine->next = newLine;
2062        }
2063    
2064        return newLine;
2065    }
2066    
2067  /* val may be NULL */  /* val may be NULL */
2068  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2069       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2070       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2071       char * val) {       const char * val) {
2072      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2073      int i;      struct keywordTypes * kw;
2074        struct singleLine tmpl;
2075    
2076      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2077   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2078      if (type != LT_TITLE || !cfi->titleBracketed)       */
2079          if (!cfi->keywords[i].key) abort();  
2080        if (type == LT_TITLE && cfi->titleBracketed) {
2081     /* we're doing a bracketed title (zipl) */
2082     tmpl.type = type;
2083     tmpl.numElements = 1;
2084     tmpl.elements = alloca(sizeof(*tmpl.elements));
2085     tmpl.elements[0].item = alloca(strlen(val)+3);
2086     sprintf(tmpl.elements[0].item, "[%s]", val);
2087     tmpl.elements[0].indent = "";
2088     val = NULL;
2089        } else if (type == LT_MENUENTRY) {
2090     char *lineend = "--class gnu-linux --class gnu --class os {";
2091     if (!val) {
2092        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2093        abort();
2094     }
2095     kw = getKeywordByType(type, cfi);
2096     if (!kw) {
2097        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2098        abort();
2099     }
2100     tmpl.indent = "";
2101     tmpl.type = type;
2102     tmpl.numElements = 3;
2103     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2104     tmpl.elements[0].item = kw->key;
2105     tmpl.elements[0].indent = alloca(2);
2106     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2107     tmpl.elements[1].item = (char *)val;
2108     tmpl.elements[1].indent = alloca(2);
2109     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2110     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2111     strcpy(tmpl.elements[2].item, lineend);
2112     tmpl.elements[2].indent = "";
2113        } else {
2114     kw = getKeywordByType(type, cfi);
2115     if (!kw) {
2116        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2117        abort();
2118     }
2119     tmpl.type = type;
2120     tmpl.numElements = val ? 2 : 1;
2121     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2122     tmpl.elements[0].item = kw->key;
2123     tmpl.elements[0].indent = alloca(2);
2124     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2125     if (val) {
2126        tmpl.elements[1].item = (char *)val;
2127        tmpl.elements[1].indent = "";
2128     }
2129        }
2130    
2131      /* 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
2132         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2133         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
2134         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2135         differently from the rest) */         differently from the rest) */
2136      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2137   line = entry->lines;   if (line->numElements) prev = line;
2138   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2139   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;  
2140      }      }
2141    
2142      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2143          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2144          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2145          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2146          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2147          line->elements[0].indent = malloc(2);   else
2148          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2149          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2150             if (menuEntry)
2151          if (val) {      tmpl.indent = "\t";
2152              line->elements[1].item = val;   else if (prev == entry->lines)
2153              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2154          }   else
2155      } 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("");  
2156      }      }
2157    
2158      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2159  }  }
2160    
2161  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2180  void removeLine(struct singleEntry * ent
2180      free(line);      free(line);
2181  }  }
2182    
2183    static int isquote(char q)
2184    {
2185        if (q == '\'' || q == '\"')
2186     return 1;
2187        return 0;
2188    }
2189    
2190    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2191    {
2192        struct singleLine newLine = {
2193     .indent = tmplLine->indent,
2194     .type = tmplLine->type,
2195     .next = tmplLine->next,
2196        };
2197        int firstQuotedItem = -1;
2198        int quoteLen = 0;
2199        int j;
2200        int element = 0;
2201        char *c;
2202    
2203        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2204        strcpy(c, tmplLine->elements[0].item);
2205        insertElement(&newLine, c, element++, cfi);
2206        free(c);
2207        c = NULL;
2208    
2209        for (j = 1; j < tmplLine->numElements; j++) {
2210     if (firstQuotedItem == -1) {
2211        quoteLen += strlen(tmplLine->elements[j].item);
2212        
2213        if (isquote(tmplLine->elements[j].item[0])) {
2214     firstQuotedItem = j;
2215            quoteLen += strlen(tmplLine->elements[j].indent);
2216        } else {
2217     c = malloc(quoteLen + 1);
2218     strcpy(c, tmplLine->elements[j].item);
2219     insertElement(&newLine, c, element++, cfi);
2220     free(c);
2221     quoteLen = 0;
2222        }
2223     } else {
2224        int itemlen = strlen(tmplLine->elements[j].item);
2225        quoteLen += itemlen;
2226        quoteLen += strlen(tmplLine->elements[j].indent);
2227        
2228        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2229     c = malloc(quoteLen + 1);
2230     c[0] = '\0';
2231     for (int i = firstQuotedItem; i < j+1; i++) {
2232        strcat(c, tmplLine->elements[i].item);
2233        strcat(c, tmplLine->elements[i].indent);
2234     }
2235     insertElement(&newLine, c, element++, cfi);
2236     free(c);
2237    
2238     firstQuotedItem = -1;
2239     quoteLen = 0;
2240        }
2241     }
2242        }
2243        while (tmplLine->numElements)
2244     removeElement(tmplLine, 0);
2245        if (tmplLine->elements)
2246     free(tmplLine->elements);
2247    
2248        tmplLine->numElements = newLine.numElements;
2249        tmplLine->elements = newLine.elements;
2250    }
2251    
2252    static void insertElement(struct singleLine * line,
2253      const char * item, int insertHere,
2254      struct configFileInfo * cfi)
2255    {
2256        struct keywordTypes * kw;
2257        char indent[2] = "";
2258    
2259        /* sanity check */
2260        if (insertHere > line->numElements) {
2261     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2262      insertHere, line->numElements);
2263     insertHere = line->numElements;
2264        }
2265    
2266        line->elements = realloc(line->elements, (line->numElements + 1) *
2267         sizeof(*line->elements));
2268        memmove(&line->elements[insertHere+1],
2269        &line->elements[insertHere],
2270        (line->numElements - insertHere) *
2271        sizeof(*line->elements));
2272        line->elements[insertHere].item = strdup(item);
2273    
2274        kw = getKeywordByType(line->type, cfi);
2275    
2276        if (line->numElements == 0) {
2277     indent[0] = '\0';
2278        } else if (insertHere == 0) {
2279     indent[0] = kw->nextChar;
2280        } else if (kw->separatorChar != '\0') {
2281     indent[0] = kw->separatorChar;
2282        } else {
2283     indent[0] = ' ';
2284        }
2285    
2286        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2287     /* move the end-of-line forward */
2288     line->elements[insertHere].indent =
2289        line->elements[insertHere-1].indent;
2290     line->elements[insertHere-1].indent = strdup(indent);
2291        } else {
2292     line->elements[insertHere].indent = strdup(indent);
2293        }
2294    
2295        line->numElements++;
2296    
2297        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2298          line->elements[0].item,
2299          line->elements[insertHere].item,
2300          line->elements[insertHere].indent,
2301          insertHere);
2302    }
2303    
2304    static void removeElement(struct singleLine * line, int removeHere) {
2305        int i;
2306    
2307        /* sanity check */
2308        if (removeHere >= line->numElements) return;
2309    
2310        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2311          removeHere, line->elements[removeHere].item);
2312    
2313        free(line->elements[removeHere].item);
2314    
2315        if (removeHere > 1) {
2316     /* previous argument gets this argument's post-indentation */
2317     free(line->elements[removeHere-1].indent);
2318     line->elements[removeHere-1].indent =
2319        line->elements[removeHere].indent;
2320        } else {
2321     free(line->elements[removeHere].indent);
2322        }
2323    
2324        /* now collapse the array, but don't bother to realloc smaller */
2325        for (i = removeHere; i < line->numElements - 1; i++)
2326     line->elements[i] = line->elements[i + 1];
2327    
2328        line->numElements--;
2329    }
2330    
2331  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2332      char * first, * second;      char * first, * second;
2333      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2350  int updateActualImage(struct grubConfig
2350      struct singleEntry * entry;      struct singleEntry * entry;
2351      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2352      int index = 0;      int index = 0;
2353      int i, j, k;      int i, k;
2354      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2355      const char ** arg;      const char ** arg;
2356      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2357      int firstElement;      int firstElement;
2358      int *usedElements, *usedArgs;      int *usedElements;
2359        int doreplace;
2360    
2361      if (!image) return 0;      if (!image) return 0;
2362    
# Line 1609  int updateActualImage(struct grubConfig Line 2383  int updateActualImage(struct grubConfig
2383   }   }
2384      }      }
2385    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2386    
2387      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2388   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2389    
2390      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2391   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2392    
2393      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2394    
2395      k = 0;   if (multibootArgs && !entry->multiboot)
2396      for (arg = newArgs; *arg; arg++)      continue;
2397          k++;  
2398      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2399     * LT_KERNELARGS, use that.  Otherwise use
2400     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2401     */
2402     if (useKernelArgs) {
2403        line = getLineByType(LT_KERNELARGS, entry->lines);
2404        if (!line) {
2405     /* no LT_KERNELARGS, need to add it */
2406     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2407           cfg->secondaryIndent, NULL);
2408        }
2409        firstElement = 1;
2410    
2411      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2412   index++;      line = getLineByType(LT_HYPER, entry->lines);
2413        if (!line) {
2414     /* a multiboot entry without LT_HYPER? */
2415     continue;
2416        }
2417        firstElement = 2;
2418    
2419   line = entry->lines;   } else {
2420   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2421   if (!line) continue;      if (!line) {
2422   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2423     continue;
2424          if (entry->multiboot && !multibootArgs) {      }
2425              /* 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;  
2426   }   }
2427    
2428   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2429      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2430      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2431     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2432        /* this is a multiboot entry, make sure there's
2433         * -- on the args line
2434         */
2435        for (i = firstElement; i < line->numElements; i++) {
2436     if (!strcmp(line->elements[i].item, "--"))
2437        break;
2438        }
2439        if (i == line->numElements) {
2440     /* assume all existing args are kernel args,
2441     * prepend -- to make it official
2442     */
2443     insertElement(line, "--", firstElement, cfg->cfi);
2444     i = firstElement;
2445        }
2446        if (!multibootArgs) {
2447     /* kernel args start after the -- */
2448     firstElement = i + 1;
2449        }
2450     } else if (cfg->cfi->mbConcatArgs) {
2451        /* this is a non-multiboot entry, remove hyper args */
2452        for (i = firstElement; i < line->numElements; i++) {
2453     if (!strcmp(line->elements[i].item, "--"))
2454        break;
2455        }
2456        if (i < line->numElements) {
2457     /* remove args up to -- */
2458     while (strcmp(line->elements[firstElement].item, "--"))
2459        removeElement(line, firstElement);
2460     /* remove -- */
2461     removeElement(line, firstElement);
2462        }
2463   }   }
2464    
2465          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2466    
2467          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2468   for (arg = newArgs; *arg; arg++) {  
2469              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2470      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2471     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2472        !strcmp(line->elements[i].item, "--"))
2473     {
2474        /* reached the end of hyper args, insert here */
2475        doreplace = 0;
2476        break;  
2477     }
2478                  if (usedElements[i])                  if (usedElements[i])
2479                      continue;                      continue;
2480   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2481                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2482      break;      break;
2483                  }                  }
2484              }              }
     chptr = strchr(*arg, '=');  
2485    
2486      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2487   /* replace */   /* direct replacement */
2488   free(line->elements[i].item);   free(line->elements[i].item);
2489   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("");  
  }  
2490    
2491   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2492   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2493      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2494   /* append */   if (rootLine) {
2495   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2496   (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(" ");  
2497   } else {   } else {
2498      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2499         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2500   }   }
2501        }
2502    
2503   line->numElements++;      else {
2504     /* insert/append */
2505     insertElement(line, *arg, i, cfg->cfi);
2506     usedElements = realloc(usedElements, line->numElements *
2507           sizeof(*usedElements));
2508     memmove(&usedElements[i + 1], &usedElements[i],
2509     line->numElements - i - 1);
2510     usedElements[i] = 1;
2511    
2512   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2513     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2514     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2515   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2516      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2517      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2518   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2519   }   }
2520      }      }
             k++;  
2521   }   }
2522    
2523          free(usedElements);          free(usedElements);
2524    
  /* 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? */  
2525   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2526      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2527   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2528        !strcmp(line->elements[i].item, "--"))
2529        /* reached the end of hyper args, stop here */
2530        break;
2531     if (!argMatch(line->elements[i].item, *arg)) {
2532        removeElement(line, i);
2533      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;  
2534   }   }
2535        }
2536   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2537        if (useRoot && !strncmp(*arg, "root=", 5)) {
2538   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2539      line->elements[j - 1] = line->elements[j];   if (rootLine)
2540        removeLine(entry, rootLine);
  line->numElements--;  
2541      }      }
2542   }   }
2543    
# Line 1760  int updateActualImage(struct grubConfig Line 2548  int updateActualImage(struct grubConfig
2548   }   }
2549      }      }
2550    
     free(usedArgs);  
2551      free(newArgs);      free(newArgs);
2552      free(oldArgs);      free(oldArgs);
2553    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2573  int updateImage(struct grubConfig * cfg,
2573      return rc;      return rc;
2574  }  }
2575    
2576    int updateInitrd(struct grubConfig * cfg, const char * image,
2577                     const char * prefix, const char * initrd) {
2578        struct singleEntry * entry;
2579        struct singleLine * line, * kernelLine, *endLine = NULL;
2580        int index = 0;
2581    
2582        if (!image) return 0;
2583    
2584        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2585            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2586            if (!kernelLine) continue;
2587    
2588            line = getLineByType(LT_INITRD, entry->lines);
2589            if (line)
2590                removeLine(entry, line);
2591            if (prefix) {
2592                int prefixLen = strlen(prefix);
2593                if (!strncmp(initrd, prefix, prefixLen))
2594                    initrd += prefixLen;
2595            }
2596     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2597     if (endLine)
2598        removeLine(entry, endLine);
2599            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2600            if (!line)
2601        return 1;
2602     if (endLine) {
2603        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2604                if (!line)
2605     return 1;
2606     }
2607    
2608            break;
2609        }
2610    
2611        return 0;
2612    }
2613    
2614  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2615      int fd;      int fd;
2616      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2634  int checkDeviceBootloader(const char * d
2634      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2635   return 0;   return 0;
2636    
2637      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2638   offset = boot[2] + 2;   offset = boot[2] + 2;
2639      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2640   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2641      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2642   offset = boot[1] + 2;        offset = boot[1] + 2;
2643            /*
2644     * it looks like grub, when copying stage1 into the mbr, patches stage1
2645     * right after the JMP location, replacing other instructions such as
2646     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2647     * different bytes.
2648     */
2649          if ((bootSect[offset + 1] == NOOP_OPCODE)
2650      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2651     offset = offset + 3;
2652          }
2653      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2654   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2655      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2791  int checkForLilo(struct grubConfig * con
2791      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2792  }  }
2793    
2794    int checkForGrub2(struct grubConfig * config) {
2795        if (!access("/etc/grub.d/", R_OK))
2796     return 2;
2797    
2798        return 1;
2799    }
2800    
2801  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2802      int fd;      int fd;
2803      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2818  int checkForGrub(struct grubConfig * con
2818      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2819   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2820   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2821     close(fd);
2822     return 1;
2823        }
2824        close(fd);
2825    
2826        return checkDeviceBootloader(boot, bootSect);
2827    }
2828    
2829    int checkForExtLinux(struct grubConfig * config) {
2830        int fd;
2831        unsigned char bootSect[512];
2832        char * boot;
2833        char executable[] = "/boot/extlinux/extlinux";
2834    
2835        printf("entered: checkForExtLinux()\n");
2836    
2837        if (parseSysconfigGrub(NULL, &boot))
2838     return 0;
2839    
2840        /* assume grub is not installed -- not an error condition */
2841        if (!boot)
2842     return 0;
2843    
2844        fd = open(executable, O_RDONLY);
2845        if (fd < 0)
2846     /* this doesn't exist if grub hasn't been installed */
2847     return 0;
2848    
2849        if (read(fd, bootSect, 512) != 512) {
2850     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2851     executable, strerror(errno));
2852   return 1;   return 1;
2853      }      }
2854      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2867  static char * getRootSpecifier(char * st
2867      return rootspec;      return rootspec;
2868  }  }
2869    
2870    static char * getInitrdVal(struct grubConfig * config,
2871       const char * prefix, struct singleLine *tmplLine,
2872       const char * newKernelInitrd,
2873       char ** extraInitrds, int extraInitrdCount)
2874    {
2875        char *initrdVal, *end;
2876        int i;
2877        size_t totalSize;
2878        size_t prefixLen;
2879        char separatorChar;
2880    
2881        prefixLen = strlen(prefix);
2882        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2883    
2884        for (i = 0; i < extraInitrdCount; i++) {
2885     totalSize += sizeof(separatorChar);
2886     totalSize += strlen(extraInitrds[i]) - prefixLen;
2887        }
2888    
2889        initrdVal = end = malloc(totalSize);
2890    
2891        end = stpcpy (end, newKernelInitrd + prefixLen);
2892    
2893        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2894        for (i = 0; i < extraInitrdCount; i++) {
2895     const char *extraInitrd;
2896     int j;
2897    
2898     extraInitrd = extraInitrds[i] + prefixLen;
2899     /* Don't add entries that are already there */
2900     if (tmplLine != NULL) {
2901        for (j = 2; j < tmplLine->numElements; j++)
2902     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2903        break;
2904    
2905        if (j != tmplLine->numElements)
2906     continue;
2907     }
2908    
2909     *end++ = separatorChar;
2910     end = stpcpy(end, extraInitrd);
2911        }
2912    
2913        return initrdVal;
2914    }
2915    
2916  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2917           const char * prefix,           const char * prefix,
2918   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2919   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2920     char ** extraInitrds, int extraInitrdCount,
2921                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2922      struct singleEntry * new;      struct singleEntry * new;
2923      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2924      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2925      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2926    
2927      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2928    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2952  int addNewKernel(struct grubConfig * con
2952      config->entries = new;      config->entries = new;
2953    
2954      /* copy/update from the template */      /* copy/update from the template */
2955      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2956        if (newKernelInitrd)
2957     needs |= NEED_INITRD;
2958      if (newMBKernel) {      if (newMBKernel) {
2959          needs |= KERNEL_MB;          needs |= NEED_MB;
2960          new->multiboot = 1;          new->multiboot = 1;
2961      }      }
2962    
2963      if (template) {      if (template) {
2964   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2965      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2966      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2967   indent = tmplLine->indent;   {
2968        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2969    
2970      /* skip comments */      /* skip comments */
2971      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2972      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2973      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2974    
2975      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2976      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2977     if (!template->multiboot && (needs & NEED_MB)) {
2978              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2979                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2980                  struct singleLine *l;       * hypervisor at the same time.
2981                  needs &= ~ KERNEL_MB;       */
2982        if (config->cfi->mbHyperFirst) {
2983                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2984                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2985                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2986                      newMBKernel + strlen(prefix));
2987                  tmplLine = lastLine;   /* set up for adding the kernel line */
2988                  if (!new->lines) {   free(tmplLine->indent);
2989                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2990                  } else {   needs &= ~NEED_MB;
2991                      newLine->next = l;      }
2992                      newLine = l;      if (needs & NEED_KERNEL) {
2993                  }   /* use addLineTmpl to preserve line elements,
2994                  continue;   * otherwise we could just call addLine.  Unfortunately
2995              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2996                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2997                  continue; /* don't need multiboot kernel here */   * change below.
2998              }   */
2999     struct keywordTypes * mbm_kw =
3000        getKeywordByType(LT_MBMODULE, config->cfi);
3001     if (mbm_kw) {
3002        tmplLine->type = LT_MBMODULE;
3003        free(tmplLine->elements[0].item);
3004        tmplLine->elements[0].item = strdup(mbm_kw->key);
3005     }
3006     newLine = addLineTmpl(new, tmplLine, newLine,
3007          newKernelPath + strlen(prefix), config->cfi);
3008     needs &= ~NEED_KERNEL;
3009        }
3010        if (needs & NEED_MB) { /* !mbHyperFirst */
3011     newLine = addLine(new, config->cfi, LT_HYPER,
3012      config->secondaryIndent,
3013      newMBKernel + strlen(prefix));
3014     needs &= ~NEED_MB;
3015        }
3016     } else if (needs & NEED_KERNEL) {
3017        newLine = addLineTmpl(new, tmplLine, newLine,
3018      newKernelPath + strlen(prefix), config->cfi);
3019        needs &= ~NEED_KERNEL;
3020     }
3021    
3022      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3023   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3024   new->lines = newLine;   if (needs & NEED_MB) {
3025      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3026   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3027   newLine = newLine->next;      needs &= ~NEED_MB;
3028      }   }
3029    
3030        } else if (tmplLine->type == LT_MBMODULE &&
3031           tmplLine->numElements >= 2) {
3032     if (new->multiboot) {
3033        if (needs & NEED_KERNEL) {
3034     newLine = addLineTmpl(new, tmplLine, newLine,
3035          newKernelPath +
3036          strlen(prefix), config->cfi);
3037     needs &= ~NEED_KERNEL;
3038        } else if (config->cfi->mbInitRdIsModule &&
3039           (needs & NEED_INITRD)) {
3040     char *initrdVal;
3041     initrdVal = getInitrdVal(config, prefix, tmplLine,
3042     newKernelInitrd, extraInitrds,
3043     extraInitrdCount);
3044     newLine = addLineTmpl(new, tmplLine, newLine,
3045          initrdVal, config->cfi);
3046     free(initrdVal);
3047     needs &= ~NEED_INITRD;
3048        }
3049     } else if (needs & NEED_KERNEL) {
3050        /* template is multi but new is not,
3051         * insert the kernel in the first module slot
3052         */
3053        tmplLine->type = LT_KERNEL;
3054        free(tmplLine->elements[0].item);
3055        tmplLine->elements[0].item =
3056     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3057        newLine = addLineTmpl(new, tmplLine, newLine,
3058      newKernelPath + strlen(prefix), config->cfi);
3059        needs &= ~NEED_KERNEL;
3060     } else if (needs & NEED_INITRD) {
3061        char *initrdVal;
3062        /* template is multi but new is not,
3063         * insert the initrd in the second module slot
3064         */
3065        tmplLine->type = LT_INITRD;
3066        free(tmplLine->elements[0].item);
3067        tmplLine->elements[0].item =
3068     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3069        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3070        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3071        free(initrdVal);
3072        needs &= ~NEED_INITRD;
3073     }
3074    
     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));  
                 }  
3075      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3076      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3077   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3078   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3079                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3080                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3081                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3082                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3083                  }       */
3084                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3085                  if (rootspec != NULL) {   char *initrdVal;
3086                      newLine->elements[1].item = sdupprintf("%s%s",  
3087                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3088                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3089                                                             strlen(prefix));    config->secondaryIndent,
3090                  } else {    initrdVal);
3091                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3092                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3093                  }      }
3094              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3095                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3096   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3097                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3098                      free(newLine->elements[0].item);      free(initrdVal);
3099                      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);  
3100   }   }
3101    
3102   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3103   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3104   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3105     char *nkt = malloc(strlen(newKernelTitle)+3);
3106     strcpy(nkt, "'");
3107     strcat(nkt, newKernelTitle);
3108     strcat(nkt, "'");
3109     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3110     free(nkt);
3111     needs &= ~NEED_TITLE;
3112      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3113                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3114                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3115                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3116                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3117                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3118                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3119                                             newLine->numElements);     config->cfi->titleBracketed) {
3120        /* addLineTmpl doesn't handle titleBracketed */
3121                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3122                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3123                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3124                  newLine->numElements = 1;   }
3125              }      } else if (tmplLine->type == LT_ECHO) {
3126        requote(tmplLine, config->cfi);
3127        static const char *prefix = "'Loading ";
3128        if (tmplLine->numElements > 1 &&
3129        strstr(tmplLine->elements[1].item, prefix) &&
3130        masterLine->next && masterLine->next->type == LT_KERNEL) {
3131     char *newTitle = malloc(strlen(prefix) +
3132     strlen(newKernelTitle) + 2);
3133    
3134     strcpy(newTitle, prefix);
3135     strcat(newTitle, newKernelTitle);
3136     strcat(newTitle, "'");
3137     newLine = addLine(new, config->cfi, LT_ECHO,
3138     tmplLine->indent, newTitle);
3139     free(newTitle);
3140        } else {
3141     /* pass through other lines from the template */
3142     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3143     config->cfi);
3144        }
3145        } else {
3146     /* pass through other lines from the template */
3147     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3148        }
3149   }   }
3150    
3151      } else {      } else {
3152   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3153      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3154     */
3155     switch (config->cfi->entryStart) {
3156        case LT_KERNEL:
3157     if (new->multiboot && config->cfi->mbHyperFirst) {
3158        /* fall through to LT_HYPER */
3159     } else {
3160        newLine = addLine(new, config->cfi, LT_KERNEL,
3161          config->primaryIndent,
3162          newKernelPath + strlen(prefix));
3163        needs &= ~NEED_KERNEL;
3164        break;
3165     }
3166    
3167        case LT_HYPER:
3168     newLine = addLine(new, config->cfi, LT_HYPER,
3169      config->primaryIndent,
3170      newMBKernel + strlen(prefix));
3171     needs &= ~NEED_MB;
3172   break;   break;
         }  
3173    
3174   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3175      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3176       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3177       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3178      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3179       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3180      default:        config->primaryIndent, nkt);
3181                  /* zipl strikes again */   free(nkt);
3182                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3183                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3184                      chptr = newKernelTitle;   break;
3185                      type = LT_TITLE;      }
3186                      break;      case LT_TITLE:
3187                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3188                      abort();   char * templabel;
3189                  }   int x = 0, y = 0;
3190   }  
3191     templabel = strdup(newKernelTitle);
3192     while( templabel[x]){
3193     if( templabel[x] == ' ' ){
3194     y = x;
3195     while( templabel[y] ){
3196     templabel[y] = templabel[y+1];
3197     y++;
3198     }
3199     }
3200     x++;
3201     }
3202     newLine = addLine(new, config->cfi, LT_TITLE,
3203      config->primaryIndent, templabel);
3204     free(templabel);
3205     }else{
3206     newLine = addLine(new, config->cfi, LT_TITLE,
3207      config->primaryIndent, newKernelTitle);
3208     }
3209     needs &= ~NEED_TITLE;
3210     break;
3211    
3212   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3213   new->lines = newLine;   abort();
3214     }
3215      }      }
3216    
3217      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3218          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3219              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3220                                config->secondaryIndent,       */
3221                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3222          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3223              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3224                                config->secondaryIndent,    newKernelTitle);
3225                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3226          /* don't need to check for title as it's guaranteed to have been      }
3227           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3228           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3229          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3230              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3231                                config->secondaryIndent,   needs &= ~NEED_MB;
3232                                newKernelInitrd + strlen(prefix));      }
3233      } else {      if (needs & NEED_KERNEL) {
3234          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3235              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3236                                config->secondaryIndent,        config->cfi)) ?
3237                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3238          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3239              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3240                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3241                                newKernelTitle);      }
3242          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3243              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3244                                config->secondaryIndent,    config->secondaryIndent,
3245                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3246     needs &= ~NEED_MB;
3247        }
3248        if (needs & NEED_INITRD) {
3249     char *initrdVal;
3250     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3251     newLine = addLine(new, config->cfi,
3252      (new->multiboot && getKeywordByType(LT_MBMODULE,
3253          config->cfi)) ?
3254      LT_MBMODULE : LT_INITRD,
3255      config->secondaryIndent,
3256      initrdVal);
3257     free(initrdVal);
3258     needs &= ~NEED_INITRD;
3259        }
3260        if (needs & NEED_END) {
3261     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3262     config->secondaryIndent, NULL);
3263     needs &= ~NEED_END;
3264        }
3265    
3266        if (needs) {
3267     printf(_("grubby: needs=%d, aborting\n"), needs);
3268     abort();
3269      }      }
3270    
3271      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3274  int addNewKernel(struct grubConfig * con
3274      return 0;      return 0;
3275  }  }
3276    
3277    static void traceback(int signum)
3278    {
3279        void *array[40];
3280        size_t size;
3281    
3282        signal(SIGSEGV, SIG_DFL);
3283        memset(array, '\0', sizeof (array));
3284        size = backtrace(array, 40);
3285    
3286        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3287                (unsigned long)size);
3288        backtrace_symbols_fd(array, size, STDERR_FILENO);
3289        exit(1);
3290    }
3291    
3292  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3293      poptContext optCon;      poptContext optCon;
3294      char * grubConfig = NULL;      const char * grubConfig = NULL;
3295      char * outputFile = NULL;      char * outputFile = NULL;
3296      int arg = 0;      int arg = 0;
3297      int flags = 0;      int flags = 0;
3298      int badImageOkay = 0;      int badImageOkay = 0;
3299        int configureGrub2 = 0;
3300      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3301      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3302        int configureExtLinux = 0;
3303      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3304        int extraInitrdCount = 0;
3305      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3306      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3307      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3317  int main(int argc, const char ** argv) {
3317      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3318      char * removeArgs = NULL;      char * removeArgs = NULL;
3319      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3320        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3321      const char * chptr = NULL;      const char * chptr = NULL;
3322      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3323      struct grubConfig * config;      struct grubConfig * config;
3324      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3325      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3326      int displayDefault = 0;      int displayDefault = 0;
3327        int displayDefaultIndex = 0;
3328        int displayDefaultTitle = 0;
3329      struct poptOption options[] = {      struct poptOption options[] = {
3330   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3331      _("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 3356  int main(int argc, const char ** argv) {
3356        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3357        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3358        "template"), NULL },        "template"), NULL },
3359     { "debug", 0, 0, &debug, 0,
3360        _("print debugging information for failures") },
3361   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3362      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3363     { "default-index", 0, 0, &displayDefaultIndex, 0,
3364        _("display the index of the default kernel") },
3365     { "default-title", 0, 0, &displayDefaultTitle, 0,
3366        _("display the title of the default kernel") },
3367   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3368      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3369     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3370        _("configure extlinux bootloader (from syslinux)") },
3371   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3372      _("configure grub bootloader") },      _("configure grub bootloader") },
3373     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3374        _("configure grub2 bootloader") },
3375   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3376      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3377      _("kernel-path") },      _("kernel-path") },
3378   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3379      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3380     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3381        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3382   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3383      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3384   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3415  int main(int argc, const char ** argv) {
3415   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3416      };      };
3417    
3418        useextlinuxmenu=0;
3419    
3420        signal(SIGSEGV, traceback);
3421    
3422      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3423      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3424    
# Line 2391  int main(int argc, const char ** argv) { Line 3428  int main(int argc, const char ** argv) {
3428      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3429      exit(0);      exit(0);
3430      break;      break;
3431      case 'i':
3432        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3433         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3434        } else {
3435     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3436     return 1;
3437        }
3438        break;
3439   }   }
3440      }      }
3441    
# Line 2406  int main(int argc, const char ** argv) { Line 3451  int main(int argc, const char ** argv) {
3451   return 1;   return 1;
3452      }      }
3453    
3454      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3455   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3456     configureExtLinux ) > 1) {
3457   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3458   return 1;   return 1;
3459      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3460   fprintf(stderr,   fprintf(stderr,
3461      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3462   return 1;   return 1;
3463        } else if (configureGrub2) {
3464     cfi = &grub2ConfigType;
3465      } else if (configureLilo) {      } else if (configureLilo) {
3466   cfi = &liloConfigType;   cfi = &liloConfigType;
3467      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3474  int main(int argc, const char ** argv) {
3474          cfi = &siloConfigType;          cfi = &siloConfigType;
3475      } else if (configureZipl) {      } else if (configureZipl) {
3476          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3477        } else if (configureExtLinux) {
3478     cfi = &extlinuxConfigType;
3479     useextlinuxmenu=1;
3480      }      }
3481    
3482      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3491  int main(int argc, const char ** argv) {
3491        #elif __s390x__        #elif __s390x__
3492          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3493        #else        #else
3494   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3495        cfi = &grub2ConfigType;
3496     else
3497        cfi = &grubConfigType;
3498        #endif        #endif
3499      }      }
3500    
3501      if (!grubConfig)      if (!grubConfig) {
3502   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3503        grubConfig = cfi->findConfig(cfi);
3504     if (!grubConfig)
3505        grubConfig = cfi->defaultConfig;
3506        }
3507    
3508      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3509    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3510    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3511   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3512    "specified option"));    "specified option"));
3513   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3523  int main(int argc, const char ** argv) {
3523      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3524   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3525   return 1;   return 1;
3526      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3527    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3528    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3529   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3530   return 1;   return 1;
3531      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3550  int main(int argc, const char ** argv) {
3550   defaultKernel = NULL;   defaultKernel = NULL;
3551      }      }
3552    
3553      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3554   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3555   "is used\n"));   "is used\n"));
3556   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3558  int main(int argc, const char ** argv) {
3558    
3559      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3560   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3561          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3562   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3563   return 1;   return 1;
3564      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3578  int main(int argc, const char ** argv) {
3578   bootPrefix = "";   bootPrefix = "";
3579      }      }
3580    
3581        if (!cfi->mbAllowExtraInitRds &&
3582     extraInitrdCount > 0) {
3583     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3584     return 1;
3585        }
3586    
3587      if (bootloaderProbe) {      if (bootloaderProbe) {
3588   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3589   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3590    
3591   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3592      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3593        gconfig = readConfig(grub2config, &grub2ConfigType);
3594        if (!gconfig)
3595     gr2c = 1;
3596        else
3597     gr2c = checkForGrub2(gconfig);
3598     }
3599    
3600     const char *grubconfig = grubFindConfig(&grubConfigType);
3601     if (!access(grubconfig, F_OK)) {
3602        gconfig = readConfig(grubconfig, &grubConfigType);
3603      if (!gconfig)      if (!gconfig)
3604   grc = 1;   grc = 1;
3605      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3614  int main(int argc, const char ** argv) {
3614   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3615   }   }
3616    
3617   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3618        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3619        if (!lconfig)
3620     erc = 1;
3621        else
3622     erc = checkForExtLinux(lconfig);
3623     }
3624    
3625     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3626    
3627   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3628     if (gr2c == 2) printf("grub2\n");
3629   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3630     if (erc == 2) printf("extlinux\n");
3631    
3632   return 0;   return 0;
3633      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3645  int main(int argc, const char ** argv) {
3645   if (!entry) return 0;   if (!entry) return 0;
3646   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3647    
3648   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3649   if (!line) return 0;   if (!line) return 0;
3650    
3651          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3653  int main(int argc, const char ** argv) {
3653                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3654    
3655   return 0;   return 0;
3656    
3657        } else if (displayDefaultTitle) {
3658     struct singleLine * line;
3659     struct singleEntry * entry;
3660    
3661     if (config->defaultImage == -1) return 0;
3662     entry = findEntryByIndex(config, config->defaultImage);
3663     if (!entry) return 0;
3664    
3665     if (!configureGrub2) {
3666      line = getLineByType(LT_TITLE, entry->lines);
3667      if (!line) return 0;
3668      printf("%s\n", line->elements[1].item);
3669    
3670     } else {
3671      char * title;
3672    
3673      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3674      line = getLineByType(LT_MENUENTRY, entry->lines);
3675      if (!line) return 0;
3676      title = grub2ExtractTitle(line);
3677      if (title)
3678        printf("%s\n", title);
3679     }
3680     return 0;
3681    
3682        } else if (displayDefaultIndex) {
3683            if (config->defaultImage == -1) return 0;
3684            printf("%i\n", config->defaultImage);
3685    
3686      } else if (kernelInfo)      } else if (kernelInfo)
3687   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3688    
# Line 2585  int main(int argc, const char ** argv) { Line 3698  int main(int argc, const char ** argv) {
3698      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3699      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3700                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3701        if (updateKernelPath && newKernelInitrd) {
3702                if (updateInitrd(config, updateKernelPath, bootPrefix,
3703                                 newKernelInitrd)) return 1;
3704        }
3705      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3706                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3707                         extraInitrds, extraInitrdCount,
3708                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3709            
3710    
# Line 2597  int main(int argc, const char ** argv) { Line 3715  int main(int argc, const char ** argv) {
3715      }      }
3716    
3717      if (!outputFile)      if (!outputFile)
3718   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3719    
3720      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3721  }  }

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