Magellan Linux

Diff of /tags/grubby-8_30/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 1751 by niro, Sat Feb 18 01:10:10 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;
  if (*end) return 0;  
1565      }      }
     stat("/", &sb2);  
1566    
1567      if (sb.st_rdev != sb2.st_dev) return 0;      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        }
1573    
1574        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 1360  void displayEntry(struct singleEntry * e Line 1926  void displayEntry(struct singleEntry * e
1926      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
1927   printf("\n");   printf("\n");
1928      }      }
1929    
1930        line = getLineByType(LT_TITLE, entry->lines);
1931        if (line) {
1932     printf("title=%s\n", line->elements[1].item);
1933        } else {
1934     char * title;
1935     line = getLineByType(LT_MENUENTRY, entry->lines);
1936     title = grub2ExtractTitle(line);
1937     if (title)
1938        printf("title=%s\n", title);
1939        }
1940  }  }
1941    
1942  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1946  int parseSysconfigGrub(int * lbaPtr, cha
1946      char * start;      char * start;
1947      char * param;      char * param;
1948    
1949      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1950      if (!in) return 1;      if (!in) return 1;
1951    
1952      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 2008  int displayInfo(struct grubConfig * conf
2008   return 1;   return 1;
2009      }      }
2010    
2011      /* 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
2012         be a better way */         be a better way */
2013      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2014   dumpSysconfigGrub();   dumpSysconfigGrub();
2015      } else {      } else {
2016   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2017   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2018      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2019   }   }
2020    
2021   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2022   if (line) printf("lba\n");   if (line) printf("lba\n");
2023      }      }
2024    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2033  int displayInfo(struct grubConfig * conf
2033      return 0;      return 0;
2034  }  }
2035    
2036    struct singleLine * addLineTmpl(struct singleEntry * entry,
2037     struct singleLine * tmplLine,
2038     struct singleLine * prevLine,
2039     const char * val,
2040     struct configFileInfo * cfi)
2041    {
2042        struct singleLine * newLine = lineDup(tmplLine);
2043    
2044        if (val) {
2045     /* override the inherited value with our own.
2046     * This is a little weak because it only applies to elements[1]
2047     */
2048     if (newLine->numElements > 1)
2049        removeElement(newLine, 1);
2050     insertElement(newLine, val, 1, cfi);
2051    
2052     /* but try to keep the rootspec from the template... sigh */
2053     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2054        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2055        if (rootspec != NULL) {
2056     free(newLine->elements[1].item);
2057     newLine->elements[1].item =
2058        sdupprintf("%s%s", rootspec, val);
2059        }
2060     }
2061        }
2062    
2063        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2064          newLine->elements[0].item : "");
2065    
2066        if (!entry->lines) {
2067     /* first one on the list */
2068     entry->lines = newLine;
2069        } else if (prevLine) {
2070     /* add after prevLine */
2071     newLine->next = prevLine->next;
2072     prevLine->next = newLine;
2073        }
2074    
2075        return newLine;
2076    }
2077    
2078  /* val may be NULL */  /* val may be NULL */
2079  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2080       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2081       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2082       char * val) {       const char * val) {
2083      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2084      int i;      struct keywordTypes * kw;
2085        struct singleLine tmpl;
2086    
2087      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2088   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2089      if (type != LT_TITLE || !cfi->titleBracketed)       */
2090          if (!cfi->keywords[i].key) abort();  
2091        if (type == LT_TITLE && cfi->titleBracketed) {
2092     /* we're doing a bracketed title (zipl) */
2093     tmpl.type = type;
2094     tmpl.numElements = 1;
2095     tmpl.elements = alloca(sizeof(*tmpl.elements));
2096     tmpl.elements[0].item = alloca(strlen(val)+3);
2097     sprintf(tmpl.elements[0].item, "[%s]", val);
2098     tmpl.elements[0].indent = "";
2099     val = NULL;
2100        } else if (type == LT_MENUENTRY) {
2101     char *lineend = "--class gnu-linux --class gnu --class os {";
2102     if (!val) {
2103        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2104        abort();
2105     }
2106     kw = getKeywordByType(type, cfi);
2107     if (!kw) {
2108        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2109        abort();
2110     }
2111     tmpl.indent = "";
2112     tmpl.type = type;
2113     tmpl.numElements = 3;
2114     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2115     tmpl.elements[0].item = kw->key;
2116     tmpl.elements[0].indent = alloca(2);
2117     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2118     tmpl.elements[1].item = (char *)val;
2119     tmpl.elements[1].indent = alloca(2);
2120     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2121     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2122     strcpy(tmpl.elements[2].item, lineend);
2123     tmpl.elements[2].indent = "";
2124        } else {
2125     kw = getKeywordByType(type, cfi);
2126     if (!kw) {
2127        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2128        abort();
2129     }
2130     tmpl.type = type;
2131     tmpl.numElements = val ? 2 : 1;
2132     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2133     tmpl.elements[0].item = kw->key;
2134     tmpl.elements[0].indent = alloca(2);
2135     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2136     if (val) {
2137        tmpl.elements[1].item = (char *)val;
2138        tmpl.elements[1].indent = "";
2139     }
2140        }
2141    
2142      /* 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
2143         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2144         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
2145         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2146         differently from the rest) */         differently from the rest) */
2147      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2148   line = entry->lines;   if (line->numElements) prev = line;
2149   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2150   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;  
2151      }      }
2152    
2153      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2154          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2155          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2156          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2157          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2158          line->elements[0].indent = malloc(2);   else
2159          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2160          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2161             if (menuEntry)
2162          if (val) {      tmpl.indent = "\t";
2163              line->elements[1].item = val;   else if (prev == entry->lines)
2164              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2165          }   else
2166      } 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("");  
2167      }      }
2168    
2169      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2170  }  }
2171    
2172  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2191  void removeLine(struct singleEntry * ent
2191      free(line);      free(line);
2192  }  }
2193    
2194    static int isquote(char q)
2195    {
2196        if (q == '\'' || q == '\"')
2197     return 1;
2198        return 0;
2199    }
2200    
2201    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2202    {
2203        struct singleLine newLine = {
2204     .indent = tmplLine->indent,
2205     .type = tmplLine->type,
2206     .next = tmplLine->next,
2207        };
2208        int firstQuotedItem = -1;
2209        int quoteLen = 0;
2210        int j;
2211        int element = 0;
2212        char *c;
2213    
2214        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2215        strcpy(c, tmplLine->elements[0].item);
2216        insertElement(&newLine, c, element++, cfi);
2217        free(c);
2218        c = NULL;
2219    
2220        for (j = 1; j < tmplLine->numElements; j++) {
2221     if (firstQuotedItem == -1) {
2222        quoteLen += strlen(tmplLine->elements[j].item);
2223        
2224        if (isquote(tmplLine->elements[j].item[0])) {
2225     firstQuotedItem = j;
2226            quoteLen += strlen(tmplLine->elements[j].indent);
2227        } else {
2228     c = malloc(quoteLen + 1);
2229     strcpy(c, tmplLine->elements[j].item);
2230     insertElement(&newLine, c, element++, cfi);
2231     free(c);
2232     quoteLen = 0;
2233        }
2234     } else {
2235        int itemlen = strlen(tmplLine->elements[j].item);
2236        quoteLen += itemlen;
2237        quoteLen += strlen(tmplLine->elements[j].indent);
2238        
2239        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2240     c = malloc(quoteLen + 1);
2241     c[0] = '\0';
2242     for (int i = firstQuotedItem; i < j+1; i++) {
2243        strcat(c, tmplLine->elements[i].item);
2244        strcat(c, tmplLine->elements[i].indent);
2245     }
2246     insertElement(&newLine, c, element++, cfi);
2247     free(c);
2248    
2249     firstQuotedItem = -1;
2250     quoteLen = 0;
2251        }
2252     }
2253        }
2254        while (tmplLine->numElements)
2255     removeElement(tmplLine, 0);
2256        if (tmplLine->elements)
2257     free(tmplLine->elements);
2258    
2259        tmplLine->numElements = newLine.numElements;
2260        tmplLine->elements = newLine.elements;
2261    }
2262    
2263    static void insertElement(struct singleLine * line,
2264      const char * item, int insertHere,
2265      struct configFileInfo * cfi)
2266    {
2267        struct keywordTypes * kw;
2268        char indent[2] = "";
2269    
2270        /* sanity check */
2271        if (insertHere > line->numElements) {
2272     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2273      insertHere, line->numElements);
2274     insertHere = line->numElements;
2275        }
2276    
2277        line->elements = realloc(line->elements, (line->numElements + 1) *
2278         sizeof(*line->elements));
2279        memmove(&line->elements[insertHere+1],
2280        &line->elements[insertHere],
2281        (line->numElements - insertHere) *
2282        sizeof(*line->elements));
2283        line->elements[insertHere].item = strdup(item);
2284    
2285        kw = getKeywordByType(line->type, cfi);
2286    
2287        if (line->numElements == 0) {
2288     indent[0] = '\0';
2289        } else if (insertHere == 0) {
2290     indent[0] = kw->nextChar;
2291        } else if (kw->separatorChar != '\0') {
2292     indent[0] = kw->separatorChar;
2293        } else {
2294     indent[0] = ' ';
2295        }
2296    
2297        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2298     /* move the end-of-line forward */
2299     line->elements[insertHere].indent =
2300        line->elements[insertHere-1].indent;
2301     line->elements[insertHere-1].indent = strdup(indent);
2302        } else {
2303     line->elements[insertHere].indent = strdup(indent);
2304        }
2305    
2306        line->numElements++;
2307    
2308        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2309          line->elements[0].item,
2310          line->elements[insertHere].item,
2311          line->elements[insertHere].indent,
2312          insertHere);
2313    }
2314    
2315    static void removeElement(struct singleLine * line, int removeHere) {
2316        int i;
2317    
2318        /* sanity check */
2319        if (removeHere >= line->numElements) return;
2320    
2321        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2322          removeHere, line->elements[removeHere].item);
2323    
2324        free(line->elements[removeHere].item);
2325    
2326        if (removeHere > 1) {
2327     /* previous argument gets this argument's post-indentation */
2328     free(line->elements[removeHere-1].indent);
2329     line->elements[removeHere-1].indent =
2330        line->elements[removeHere].indent;
2331        } else {
2332     free(line->elements[removeHere].indent);
2333        }
2334    
2335        /* now collapse the array, but don't bother to realloc smaller */
2336        for (i = removeHere; i < line->numElements - 1; i++)
2337     line->elements[i] = line->elements[i + 1];
2338    
2339        line->numElements--;
2340    }
2341    
2342  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2343      char * first, * second;      char * first, * second;
2344      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2361  int updateActualImage(struct grubConfig
2361      struct singleEntry * entry;      struct singleEntry * entry;
2362      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2363      int index = 0;      int index = 0;
2364      int i, j, k;      int i, k;
2365      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2366      const char ** arg;      const char ** arg;
2367      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2368      int firstElement;      int firstElement;
2369      int *usedElements, *usedArgs;      int *usedElements;
2370        int doreplace;
2371    
2372      if (!image) return 0;      if (!image) return 0;
2373    
# Line 1609  int updateActualImage(struct grubConfig Line 2394  int updateActualImage(struct grubConfig
2394   }   }
2395      }      }
2396    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2397    
2398      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2399   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2400    
2401      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2402   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2403    
2404      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2405    
2406      k = 0;   if (multibootArgs && !entry->multiboot)
2407      for (arg = newArgs; *arg; arg++)      continue;
2408          k++;  
2409      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2410     * LT_KERNELARGS, use that.  Otherwise use
2411     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2412     */
2413     if (useKernelArgs) {
2414        line = getLineByType(LT_KERNELARGS, entry->lines);
2415        if (!line) {
2416     /* no LT_KERNELARGS, need to add it */
2417     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2418           cfg->secondaryIndent, NULL);
2419        }
2420        firstElement = 1;
2421    
2422      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2423   index++;      line = getLineByType(LT_HYPER, entry->lines);
2424        if (!line) {
2425     /* a multiboot entry without LT_HYPER? */
2426     continue;
2427        }
2428        firstElement = 2;
2429    
2430   line = entry->lines;   } else {
2431   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2432   if (!line) continue;      if (!line) {
2433   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2434     continue;
2435          if (entry->multiboot && !multibootArgs) {      }
2436              /* 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;  
2437   }   }
2438    
2439   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2440      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2441      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2442     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2443        /* this is a multiboot entry, make sure there's
2444         * -- on the args line
2445         */
2446        for (i = firstElement; i < line->numElements; i++) {
2447     if (!strcmp(line->elements[i].item, "--"))
2448        break;
2449        }
2450        if (i == line->numElements) {
2451     /* assume all existing args are kernel args,
2452     * prepend -- to make it official
2453     */
2454     insertElement(line, "--", firstElement, cfg->cfi);
2455     i = firstElement;
2456        }
2457        if (!multibootArgs) {
2458     /* kernel args start after the -- */
2459     firstElement = i + 1;
2460        }
2461     } else if (cfg->cfi->mbConcatArgs) {
2462        /* this is a non-multiboot entry, remove hyper args */
2463        for (i = firstElement; i < line->numElements; i++) {
2464     if (!strcmp(line->elements[i].item, "--"))
2465        break;
2466        }
2467        if (i < line->numElements) {
2468     /* remove args up to -- */
2469     while (strcmp(line->elements[firstElement].item, "--"))
2470        removeElement(line, firstElement);
2471     /* remove -- */
2472     removeElement(line, firstElement);
2473        }
2474   }   }
2475    
2476          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2477    
2478          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2479   for (arg = newArgs; *arg; arg++) {  
2480              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2481      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2482     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2483        !strcmp(line->elements[i].item, "--"))
2484     {
2485        /* reached the end of hyper args, insert here */
2486        doreplace = 0;
2487        break;  
2488     }
2489                  if (usedElements[i])                  if (usedElements[i])
2490                      continue;                      continue;
2491   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2492                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2493      break;      break;
2494                  }                  }
2495              }              }
     chptr = strchr(*arg, '=');  
2496    
2497      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2498   /* replace */   /* direct replacement */
2499   free(line->elements[i].item);   free(line->elements[i].item);
2500   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("");  
  }  
2501    
2502   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2503   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2504      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2505   /* append */   if (rootLine) {
2506   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2507   (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(" ");  
2508   } else {   } else {
2509      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2510         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2511   }   }
2512        }
2513    
2514   line->numElements++;      else {
2515     /* insert/append */
2516     insertElement(line, *arg, i, cfg->cfi);
2517     usedElements = realloc(usedElements, line->numElements *
2518           sizeof(*usedElements));
2519     memmove(&usedElements[i + 1], &usedElements[i],
2520     line->numElements - i - 1);
2521     usedElements[i] = 1;
2522    
2523   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2524     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2525     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2526   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2527      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2528      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2529   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2530   }   }
2531      }      }
             k++;  
2532   }   }
2533    
2534          free(usedElements);          free(usedElements);
2535    
  /* 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? */  
2536   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2537      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2538   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2539        !strcmp(line->elements[i].item, "--"))
2540        /* reached the end of hyper args, stop here */
2541        break;
2542     if (!argMatch(line->elements[i].item, *arg)) {
2543        removeElement(line, i);
2544      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;  
2545   }   }
2546        }
2547   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2548        if (useRoot && !strncmp(*arg, "root=", 5)) {
2549   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2550      line->elements[j - 1] = line->elements[j];   if (rootLine)
2551        removeLine(entry, rootLine);
  line->numElements--;  
2552      }      }
2553   }   }
2554    
# Line 1760  int updateActualImage(struct grubConfig Line 2559  int updateActualImage(struct grubConfig
2559   }   }
2560      }      }
2561    
     free(usedArgs);  
2562      free(newArgs);      free(newArgs);
2563      free(oldArgs);      free(oldArgs);
2564    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2584  int updateImage(struct grubConfig * cfg,
2584      return rc;      return rc;
2585  }  }
2586    
2587    int updateInitrd(struct grubConfig * cfg, const char * image,
2588                     const char * prefix, const char * initrd) {
2589        struct singleEntry * entry;
2590        struct singleLine * line, * kernelLine, *endLine = NULL;
2591        int index = 0;
2592    
2593        if (!image) return 0;
2594    
2595        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2596            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2597            if (!kernelLine) continue;
2598    
2599            line = getLineByType(LT_INITRD, entry->lines);
2600            if (line)
2601                removeLine(entry, line);
2602            if (prefix) {
2603                int prefixLen = strlen(prefix);
2604                if (!strncmp(initrd, prefix, prefixLen))
2605                    initrd += prefixLen;
2606            }
2607     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2608     if (endLine)
2609        removeLine(entry, endLine);
2610            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2611            if (!line)
2612        return 1;
2613     if (endLine) {
2614        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2615                if (!line)
2616     return 1;
2617     }
2618    
2619            break;
2620        }
2621    
2622        return 0;
2623    }
2624    
2625  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2626      int fd;      int fd;
2627      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2645  int checkDeviceBootloader(const char * d
2645      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2646   return 0;   return 0;
2647    
2648      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2649   offset = boot[2] + 2;   offset = boot[2] + 2;
2650      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2651   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2652      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2653   offset = boot[1] + 2;        offset = boot[1] + 2;
2654            /*
2655     * it looks like grub, when copying stage1 into the mbr, patches stage1
2656     * right after the JMP location, replacing other instructions such as
2657     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2658     * different bytes.
2659     */
2660          if ((bootSect[offset + 1] == NOOP_OPCODE)
2661      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2662     offset = offset + 3;
2663          }
2664      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2665   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2666      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2802  int checkForLilo(struct grubConfig * con
2802      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2803  }  }
2804    
2805    int checkForGrub2(struct grubConfig * config) {
2806        if (!access("/etc/grub.d/", R_OK))
2807     return 2;
2808    
2809        return 1;
2810    }
2811    
2812  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2813      int fd;      int fd;
2814      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2829  int checkForGrub(struct grubConfig * con
2829      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2830   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2831   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2832     close(fd);
2833     return 1;
2834        }
2835        close(fd);
2836    
2837        return checkDeviceBootloader(boot, bootSect);
2838    }
2839    
2840    int checkForExtLinux(struct grubConfig * config) {
2841        int fd;
2842        unsigned char bootSect[512];
2843        char * boot;
2844        char executable[] = "/boot/extlinux/extlinux";
2845    
2846        printf("entered: checkForExtLinux()\n");
2847    
2848        if (parseSysconfigGrub(NULL, &boot))
2849     return 0;
2850    
2851        /* assume grub is not installed -- not an error condition */
2852        if (!boot)
2853     return 0;
2854    
2855        fd = open(executable, O_RDONLY);
2856        if (fd < 0)
2857     /* this doesn't exist if grub hasn't been installed */
2858     return 0;
2859    
2860        if (read(fd, bootSect, 512) != 512) {
2861     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2862     executable, strerror(errno));
2863   return 1;   return 1;
2864      }      }
2865      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2878  static char * getRootSpecifier(char * st
2878      return rootspec;      return rootspec;
2879  }  }
2880    
2881    static char * getInitrdVal(struct grubConfig * config,
2882       const char * prefix, struct singleLine *tmplLine,
2883       const char * newKernelInitrd,
2884       char ** extraInitrds, int extraInitrdCount)
2885    {
2886        char *initrdVal, *end;
2887        int i;
2888        size_t totalSize;
2889        size_t prefixLen;
2890        char separatorChar;
2891    
2892        prefixLen = strlen(prefix);
2893        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2894    
2895        for (i = 0; i < extraInitrdCount; i++) {
2896     totalSize += sizeof(separatorChar);
2897     totalSize += strlen(extraInitrds[i]) - prefixLen;
2898        }
2899    
2900        initrdVal = end = malloc(totalSize);
2901    
2902        end = stpcpy (end, newKernelInitrd + prefixLen);
2903    
2904        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2905        for (i = 0; i < extraInitrdCount; i++) {
2906     const char *extraInitrd;
2907     int j;
2908    
2909     extraInitrd = extraInitrds[i] + prefixLen;
2910     /* Don't add entries that are already there */
2911     if (tmplLine != NULL) {
2912        for (j = 2; j < tmplLine->numElements; j++)
2913     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2914        break;
2915    
2916        if (j != tmplLine->numElements)
2917     continue;
2918     }
2919    
2920     *end++ = separatorChar;
2921     end = stpcpy(end, extraInitrd);
2922        }
2923    
2924        return initrdVal;
2925    }
2926    
2927  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2928           const char * prefix,           const char * prefix,
2929   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2930   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2931     char ** extraInitrds, int extraInitrdCount,
2932                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2933      struct singleEntry * new;      struct singleEntry * new;
2934      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2935      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2936      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2937    
2938      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2939    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2963  int addNewKernel(struct grubConfig * con
2963      config->entries = new;      config->entries = new;
2964    
2965      /* copy/update from the template */      /* copy/update from the template */
2966      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2967        if (newKernelInitrd)
2968     needs |= NEED_INITRD;
2969      if (newMBKernel) {      if (newMBKernel) {
2970          needs |= KERNEL_MB;          needs |= NEED_MB;
2971          new->multiboot = 1;          new->multiboot = 1;
2972      }      }
2973    
2974      if (template) {      if (template) {
2975   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2976      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2977      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2978   indent = tmplLine->indent;   {
2979        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2980    
2981      /* skip comments */      /* skip comments */
2982      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2983      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2984      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2985    
2986      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2987      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2988     if (!template->multiboot && (needs & NEED_MB)) {
2989              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2990                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2991                  struct singleLine *l;       * hypervisor at the same time.
2992                  needs &= ~ KERNEL_MB;       */
2993        if (config->cfi->mbHyperFirst) {
2994                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2995                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2996                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2997                      newMBKernel + strlen(prefix));
2998                  tmplLine = lastLine;   /* set up for adding the kernel line */
2999                  if (!new->lines) {   free(tmplLine->indent);
3000                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3001                  } else {   needs &= ~NEED_MB;
3002                      newLine->next = l;      }
3003                      newLine = l;      if (needs & NEED_KERNEL) {
3004                  }   /* use addLineTmpl to preserve line elements,
3005                  continue;   * otherwise we could just call addLine.  Unfortunately
3006              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3007                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3008                  continue; /* don't need multiboot kernel here */   * change below.
3009              }   */
3010     struct keywordTypes * mbm_kw =
3011        getKeywordByType(LT_MBMODULE, config->cfi);
3012     if (mbm_kw) {
3013        tmplLine->type = LT_MBMODULE;
3014        free(tmplLine->elements[0].item);
3015        tmplLine->elements[0].item = strdup(mbm_kw->key);
3016     }
3017     newLine = addLineTmpl(new, tmplLine, newLine,
3018          newKernelPath + strlen(prefix), config->cfi);
3019     needs &= ~NEED_KERNEL;
3020        }
3021        if (needs & NEED_MB) { /* !mbHyperFirst */
3022     newLine = addLine(new, config->cfi, LT_HYPER,
3023      config->secondaryIndent,
3024      newMBKernel + strlen(prefix));
3025     needs &= ~NEED_MB;
3026        }
3027     } else if (needs & NEED_KERNEL) {
3028        newLine = addLineTmpl(new, tmplLine, newLine,
3029      newKernelPath + strlen(prefix), config->cfi);
3030        needs &= ~NEED_KERNEL;
3031     }
3032    
3033      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3034   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3035   new->lines = newLine;   if (needs & NEED_MB) {
3036      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3037   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3038   newLine = newLine->next;      needs &= ~NEED_MB;
3039      }   }
3040    
3041        } else if (tmplLine->type == LT_MBMODULE &&
3042           tmplLine->numElements >= 2) {
3043     if (new->multiboot) {
3044        if (needs & NEED_KERNEL) {
3045     newLine = addLineTmpl(new, tmplLine, newLine,
3046          newKernelPath +
3047          strlen(prefix), config->cfi);
3048     needs &= ~NEED_KERNEL;
3049        } else if (config->cfi->mbInitRdIsModule &&
3050           (needs & NEED_INITRD)) {
3051     char *initrdVal;
3052     initrdVal = getInitrdVal(config, prefix, tmplLine,
3053     newKernelInitrd, extraInitrds,
3054     extraInitrdCount);
3055     newLine = addLineTmpl(new, tmplLine, newLine,
3056          initrdVal, config->cfi);
3057     free(initrdVal);
3058     needs &= ~NEED_INITRD;
3059        }
3060     } else if (needs & NEED_KERNEL) {
3061        /* template is multi but new is not,
3062         * insert the kernel in the first module slot
3063         */
3064        tmplLine->type = LT_KERNEL;
3065        free(tmplLine->elements[0].item);
3066        tmplLine->elements[0].item =
3067     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3068        newLine = addLineTmpl(new, tmplLine, newLine,
3069      newKernelPath + strlen(prefix), config->cfi);
3070        needs &= ~NEED_KERNEL;
3071     } else if (needs & NEED_INITRD) {
3072        char *initrdVal;
3073        /* template is multi but new is not,
3074         * insert the initrd in the second module slot
3075         */
3076        tmplLine->type = LT_INITRD;
3077        free(tmplLine->elements[0].item);
3078        tmplLine->elements[0].item =
3079     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3080        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3081        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3082        free(initrdVal);
3083        needs &= ~NEED_INITRD;
3084     }
3085    
     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));  
                 }  
3086      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3087      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3088   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3089   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3090                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3091                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3092                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3093                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3094                  }       */
3095                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3096                  if (rootspec != NULL) {   char *initrdVal;
3097                      newLine->elements[1].item = sdupprintf("%s%s",  
3098                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3099                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3100                                                             strlen(prefix));    config->secondaryIndent,
3101                  } else {    initrdVal);
3102                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3103                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3104                  }      }
3105              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3106                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3107   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3108                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3109                      free(newLine->elements[0].item);      free(initrdVal);
3110                      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);  
3111   }   }
3112    
3113   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3114   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3115   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3116     char *nkt = malloc(strlen(newKernelTitle)+3);
3117     strcpy(nkt, "'");
3118     strcat(nkt, newKernelTitle);
3119     strcat(nkt, "'");
3120     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3121     free(nkt);
3122     needs &= ~NEED_TITLE;
3123      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3124                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3125                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3126                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3127                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3128                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3129                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3130                                             newLine->numElements);     config->cfi->titleBracketed) {
3131        /* addLineTmpl doesn't handle titleBracketed */
3132                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3133                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3134                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3135                  newLine->numElements = 1;   }
3136              }      } else if (tmplLine->type == LT_ECHO) {
3137        requote(tmplLine, config->cfi);
3138        static const char *prefix = "'Loading ";
3139        if (tmplLine->numElements > 1 &&
3140        strstr(tmplLine->elements[1].item, prefix) &&
3141        masterLine->next && masterLine->next->type == LT_KERNEL) {
3142     char *newTitle = malloc(strlen(prefix) +
3143     strlen(newKernelTitle) + 2);
3144    
3145     strcpy(newTitle, prefix);
3146     strcat(newTitle, newKernelTitle);
3147     strcat(newTitle, "'");
3148     newLine = addLine(new, config->cfi, LT_ECHO,
3149     tmplLine->indent, newTitle);
3150     free(newTitle);
3151        } else {
3152     /* pass through other lines from the template */
3153     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3154     config->cfi);
3155        }
3156        } else {
3157     /* pass through other lines from the template */
3158     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3159        }
3160   }   }
3161    
3162      } else {      } else {
3163   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3164      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3165     */
3166     switch (config->cfi->entryStart) {
3167        case LT_KERNEL:
3168     if (new->multiboot && config->cfi->mbHyperFirst) {
3169        /* fall through to LT_HYPER */
3170     } else {
3171        newLine = addLine(new, config->cfi, LT_KERNEL,
3172          config->primaryIndent,
3173          newKernelPath + strlen(prefix));
3174        needs &= ~NEED_KERNEL;
3175        break;
3176     }
3177    
3178        case LT_HYPER:
3179     newLine = addLine(new, config->cfi, LT_HYPER,
3180      config->primaryIndent,
3181      newMBKernel + strlen(prefix));
3182     needs &= ~NEED_MB;
3183   break;   break;
         }  
3184    
3185   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3186      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3187       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3188       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3189      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3190       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3191      default:        config->primaryIndent, nkt);
3192                  /* zipl strikes again */   free(nkt);
3193                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3194                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3195                      chptr = newKernelTitle;   break;
3196                      type = LT_TITLE;      }
3197                      break;      case LT_TITLE:
3198                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3199                      abort();   char * templabel;
3200                  }   int x = 0, y = 0;
3201   }  
3202     templabel = strdup(newKernelTitle);
3203     while( templabel[x]){
3204     if( templabel[x] == ' ' ){
3205     y = x;
3206     while( templabel[y] ){
3207     templabel[y] = templabel[y+1];
3208     y++;
3209     }
3210     }
3211     x++;
3212     }
3213     newLine = addLine(new, config->cfi, LT_TITLE,
3214      config->primaryIndent, templabel);
3215     free(templabel);
3216     }else{
3217     newLine = addLine(new, config->cfi, LT_TITLE,
3218      config->primaryIndent, newKernelTitle);
3219     }
3220     needs &= ~NEED_TITLE;
3221     break;
3222    
3223   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3224   new->lines = newLine;   abort();
3225     }
3226      }      }
3227    
3228      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3229          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3230              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3231                                config->secondaryIndent,       */
3232                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3233          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3234              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3235                                config->secondaryIndent,    newKernelTitle);
3236                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3237          /* don't need to check for title as it's guaranteed to have been      }
3238           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3239           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3240          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3241              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3242                                config->secondaryIndent,   needs &= ~NEED_MB;
3243                                newKernelInitrd + strlen(prefix));      }
3244      } else {      if (needs & NEED_KERNEL) {
3245          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3246              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3247                                config->secondaryIndent,        config->cfi)) ?
3248                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3249          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3250              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3251                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3252                                newKernelTitle);      }
3253          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3254              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3255                                config->secondaryIndent,    config->secondaryIndent,
3256                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3257     needs &= ~NEED_MB;
3258        }
3259        if (needs & NEED_INITRD) {
3260     char *initrdVal;
3261     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3262     newLine = addLine(new, config->cfi,
3263      (new->multiboot && getKeywordByType(LT_MBMODULE,
3264          config->cfi)) ?
3265      LT_MBMODULE : LT_INITRD,
3266      config->secondaryIndent,
3267      initrdVal);
3268     free(initrdVal);
3269     needs &= ~NEED_INITRD;
3270        }
3271        if (needs & NEED_END) {
3272     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3273     config->secondaryIndent, NULL);
3274     needs &= ~NEED_END;
3275        }
3276    
3277        if (needs) {
3278     printf(_("grubby: needs=%d, aborting\n"), needs);
3279     abort();
3280      }      }
3281    
3282      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3285  int addNewKernel(struct grubConfig * con
3285      return 0;      return 0;
3286  }  }
3287    
3288    static void traceback(int signum)
3289    {
3290        void *array[40];
3291        size_t size;
3292    
3293        signal(SIGSEGV, SIG_DFL);
3294        memset(array, '\0', sizeof (array));
3295        size = backtrace(array, 40);
3296    
3297        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3298                (unsigned long)size);
3299        backtrace_symbols_fd(array, size, STDERR_FILENO);
3300        exit(1);
3301    }
3302    
3303  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3304      poptContext optCon;      poptContext optCon;
3305      char * grubConfig = NULL;      const char * grubConfig = NULL;
3306      char * outputFile = NULL;      char * outputFile = NULL;
3307      int arg = 0;      int arg = 0;
3308      int flags = 0;      int flags = 0;
3309      int badImageOkay = 0;      int badImageOkay = 0;
3310        int configureGrub2 = 0;
3311      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3312      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3313        int configureExtLinux = 0;
3314      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3315        int extraInitrdCount = 0;
3316      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3317      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3318      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3328  int main(int argc, const char ** argv) {
3328      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3329      char * removeArgs = NULL;      char * removeArgs = NULL;
3330      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3331        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3332      const char * chptr = NULL;      const char * chptr = NULL;
3333      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3334      struct grubConfig * config;      struct grubConfig * config;
3335      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3336      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3337      int displayDefault = 0;      int displayDefault = 0;
3338        int displayDefaultIndex = 0;
3339        int displayDefaultTitle = 0;
3340      struct poptOption options[] = {      struct poptOption options[] = {
3341   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3342      _("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 3367  int main(int argc, const char ** argv) {
3367        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3368        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3369        "template"), NULL },        "template"), NULL },
3370     { "debug", 0, 0, &debug, 0,
3371        _("print debugging information for failures") },
3372   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3373      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3374     { "default-index", 0, 0, &displayDefaultIndex, 0,
3375        _("display the index of the default kernel") },
3376     { "default-title", 0, 0, &displayDefaultTitle, 0,
3377        _("display the title of the default kernel") },
3378   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3379      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3380     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3381        _("configure extlinux bootloader (from syslinux)") },
3382   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3383      _("configure grub bootloader") },      _("configure grub bootloader") },
3384     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3385        _("configure grub2 bootloader") },
3386   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3387      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3388      _("kernel-path") },      _("kernel-path") },
3389   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3390      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3391     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3392        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3393   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3394      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3395   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3426  int main(int argc, const char ** argv) {
3426   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3427      };      };
3428    
3429        useextlinuxmenu=0;
3430    
3431        signal(SIGSEGV, traceback);
3432    
3433      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3434      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3435    
# Line 2391  int main(int argc, const char ** argv) { Line 3439  int main(int argc, const char ** argv) {
3439      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3440      exit(0);      exit(0);
3441      break;      break;
3442      case 'i':
3443        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3444         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3445        } else {
3446     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3447     return 1;
3448        }
3449        break;
3450   }   }
3451      }      }
3452    
# Line 2406  int main(int argc, const char ** argv) { Line 3462  int main(int argc, const char ** argv) {
3462   return 1;   return 1;
3463      }      }
3464    
3465      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3466   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3467     configureExtLinux ) > 1) {
3468   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3469   return 1;   return 1;
3470      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3471   fprintf(stderr,   fprintf(stderr,
3472      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3473   return 1;   return 1;
3474        } else if (configureGrub2) {
3475     cfi = &grub2ConfigType;
3476      } else if (configureLilo) {      } else if (configureLilo) {
3477   cfi = &liloConfigType;   cfi = &liloConfigType;
3478      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3485  int main(int argc, const char ** argv) {
3485          cfi = &siloConfigType;          cfi = &siloConfigType;
3486      } else if (configureZipl) {      } else if (configureZipl) {
3487          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3488        } else if (configureExtLinux) {
3489     cfi = &extlinuxConfigType;
3490     useextlinuxmenu=1;
3491      }      }
3492    
3493      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3502  int main(int argc, const char ** argv) {
3502        #elif __s390x__        #elif __s390x__
3503          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3504        #else        #else
3505   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3506        cfi = &grub2ConfigType;
3507     else
3508        cfi = &grubConfigType;
3509        #endif        #endif
3510      }      }
3511    
3512      if (!grubConfig)      if (!grubConfig) {
3513   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3514        grubConfig = cfi->findConfig(cfi);
3515     if (!grubConfig)
3516        grubConfig = cfi->defaultConfig;
3517        }
3518    
3519      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3520    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3521    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3522   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3523    "specified option"));    "specified option"));
3524   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3534  int main(int argc, const char ** argv) {
3534      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3535   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3536   return 1;   return 1;
3537      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3538    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3539    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3540   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3541   return 1;   return 1;
3542      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3561  int main(int argc, const char ** argv) {
3561   defaultKernel = NULL;   defaultKernel = NULL;
3562      }      }
3563    
3564      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3565   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3566   "is used\n"));   "is used\n"));
3567   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3569  int main(int argc, const char ** argv) {
3569    
3570      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3571   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3572          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3573   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3574   return 1;   return 1;
3575      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3589  int main(int argc, const char ** argv) {
3589   bootPrefix = "";   bootPrefix = "";
3590      }      }
3591    
3592        if (!cfi->mbAllowExtraInitRds &&
3593     extraInitrdCount > 0) {
3594     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3595     return 1;
3596        }
3597    
3598      if (bootloaderProbe) {      if (bootloaderProbe) {
3599   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3600   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3601    
3602   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3603      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3604        gconfig = readConfig(grub2config, &grub2ConfigType);
3605        if (!gconfig)
3606     gr2c = 1;
3607        else
3608     gr2c = checkForGrub2(gconfig);
3609     }
3610    
3611     const char *grubconfig = grubFindConfig(&grubConfigType);
3612     if (!access(grubconfig, F_OK)) {
3613        gconfig = readConfig(grubconfig, &grubConfigType);
3614      if (!gconfig)      if (!gconfig)
3615   grc = 1;   grc = 1;
3616      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3625  int main(int argc, const char ** argv) {
3625   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3626   }   }
3627    
3628   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3629        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3630        if (!lconfig)
3631     erc = 1;
3632        else
3633     erc = checkForExtLinux(lconfig);
3634     }
3635    
3636     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3637    
3638   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3639     if (gr2c == 2) printf("grub2\n");
3640   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3641     if (erc == 2) printf("extlinux\n");
3642    
3643   return 0;   return 0;
3644      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3656  int main(int argc, const char ** argv) {
3656   if (!entry) return 0;   if (!entry) return 0;
3657   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3658    
3659   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3660   if (!line) return 0;   if (!line) return 0;
3661    
3662          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3664  int main(int argc, const char ** argv) {
3664                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3665    
3666   return 0;   return 0;
3667    
3668        } else if (displayDefaultTitle) {
3669     struct singleLine * line;
3670     struct singleEntry * entry;
3671    
3672     if (config->defaultImage == -1) return 0;
3673     entry = findEntryByIndex(config, config->defaultImage);
3674     if (!entry) return 0;
3675    
3676     if (!configureGrub2) {
3677      line = getLineByType(LT_TITLE, entry->lines);
3678      if (!line) return 0;
3679      printf("%s\n", line->elements[1].item);
3680    
3681     } else {
3682      char * title;
3683    
3684      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3685      line = getLineByType(LT_MENUENTRY, entry->lines);
3686      if (!line) return 0;
3687      title = grub2ExtractTitle(line);
3688      if (title)
3689        printf("%s\n", title);
3690     }
3691     return 0;
3692    
3693        } else if (displayDefaultIndex) {
3694            if (config->defaultImage == -1) return 0;
3695            printf("%i\n", config->defaultImage);
3696    
3697      } else if (kernelInfo)      } else if (kernelInfo)
3698   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3699    
# Line 2585  int main(int argc, const char ** argv) { Line 3709  int main(int argc, const char ** argv) {
3709      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3710      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3711                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3712        if (updateKernelPath && newKernelInitrd) {
3713                if (updateInitrd(config, updateKernelPath, bootPrefix,
3714                                 newKernelInitrd)) return 1;
3715        }
3716      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3717                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3718                         extraInitrds, extraInitrdCount,
3719                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3720            
3721    
# Line 2597  int main(int argc, const char ** argv) { Line 3726  int main(int argc, const char ** argv) {
3726      }      }
3727    
3728      if (!outputFile)      if (!outputFile)
3729   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3730    
3731      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3732  }  }

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