Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 920 by niro, Wed Oct 28 09:50:42 2009 UTC trunk/grubby/grubby.c revision 2972 by niro, Thu Jun 30 10:17:00 2016 UTC
# Line 36  Line 36 
36  #include <signal.h>  #include <signal.h>
37  #include <blkid/blkid.h>  #include <blkid/blkid.h>
38    
39    #include "log.h"
40    
41    #ifndef DEBUG
42  #define DEBUG 0  #define DEBUG 0
43    #endif
44    
45  #if DEBUG  #if DEBUG
46  #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)  #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
# Line 44  Line 48 
48  #define dbgPrintf(format, args...)  #define dbgPrintf(format, args...)
49  #endif  #endif
50    
51    int debug = 0; /* Currently just for template debugging */
52    
53  #define _(A) (A)  #define _(A) (A)
54    
55  #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */  #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
56  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
57    
58    #define NOOP_OPCODE 0x90
59    #define JMP_SHORT_OPCODE 0xeb
60    
61    int isEfi = 0;
62    
63    #if defined(__aarch64__)
64    #define isEfiOnly 1
65    #else
66    #define isEfiOnly 0
67    #endif
68    
69    char *saved_command_line = NULL;
70    
71  /* comments get lumped in with indention */  /* comments get lumped in with indention */
72  struct lineElement {  struct lineElement {
73      char * item;      char * item;
# Line 56  struct lineElement { Line 75  struct lineElement {
75  };  };
76    
77  enum lineType_e {  enum lineType_e {
78      LT_WHITESPACE = 1 << 0,      LT_WHITESPACE   = 1 << 0,
79      LT_TITLE      = 1 << 1,      LT_TITLE        = 1 << 1,
80      LT_KERNEL     = 1 << 2,      LT_KERNEL       = 1 << 2,
81      LT_INITRD     = 1 << 3,      LT_INITRD       = 1 << 3,
82      LT_HYPER      = 1 << 4,      LT_HYPER        = 1 << 4,
83      LT_DEFAULT    = 1 << 5,      LT_DEFAULT      = 1 << 5,
84      LT_MBMODULE   = 1 << 6,      LT_MBMODULE     = 1 << 6,
85      LT_ROOT       = 1 << 7,      LT_ROOT         = 1 << 7,
86      LT_FALLBACK   = 1 << 8,      LT_FALLBACK     = 1 << 8,
87      LT_KERNELARGS = 1 << 9,      LT_KERNELARGS   = 1 << 9,
88      LT_BOOT       = 1 << 10,      LT_BOOT         = 1 << 10,
89      LT_BOOTROOT   = 1 << 11,      LT_BOOTROOT     = 1 << 11,
90      LT_LBA        = 1 << 12,      LT_LBA          = 1 << 12,
91      LT_OTHER      = 1 << 13,      LT_OTHER        = 1 << 13,
92      LT_GENERIC    = 1 << 14,      LT_GENERIC      = 1 << 14,
93      LT_UNKNOWN    = 1 << 15,      LT_ECHO    = 1 << 16,
94        LT_MENUENTRY    = 1 << 17,
95        LT_ENTRY_END    = 1 << 18,
96        LT_SET_VARIABLE = 1 << 19,
97        LT_KERNEL_EFI   = 1 << 20,
98        LT_INITRD_EFI   = 1 << 21,
99        LT_KERNEL_16    = 1 << 22,
100        LT_INITRD_16    = 1 << 23,
101        LT_DEVTREE      = 1 << 24,
102        LT_UNKNOWN      = 1 << 25,
103  };  };
104    
105  struct singleLine {  struct singleLine {
# Line 99  struct singleEntry { Line 127  struct singleEntry {
127  #define NEED_TITLE   (1 << 2)  #define NEED_TITLE   (1 << 2)
128  #define NEED_ARGS    (1 << 3)  #define NEED_ARGS    (1 << 3)
129  #define NEED_MB      (1 << 4)  #define NEED_MB      (1 << 4)
130    #define NEED_END     (1 << 5)
131    #define NEED_DEVTREE (1 << 6)
132    
133  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
134  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
135    #define DEFAULT_SAVED_GRUB2 -3
136    
137  struct keywordTypes {  struct keywordTypes {
138      char * key;      char * key;
# Line 110  struct keywordTypes { Line 141  struct keywordTypes {
141      char separatorChar;      char separatorChar;
142  };  };
143    
144    struct configFileInfo;
145    
146    typedef const char *(*findConfigFunc)(struct configFileInfo *);
147    typedef const int (*writeLineFunc)(struct configFileInfo *,
148     struct singleLine *line);
149    typedef char *(*getEnvFunc)(struct configFileInfo *, char *name);
150    typedef int (*setEnvFunc)(struct configFileInfo *, char *name, char *value);
151    
152  struct configFileInfo {  struct configFileInfo {
153      char * defaultConfig;      char * defaultConfig;
154        findConfigFunc findConfig;
155        writeLineFunc writeLine;
156        getEnvFunc getEnv;
157        setEnvFunc setEnv;
158      struct keywordTypes * keywords;      struct keywordTypes * keywords;
159        int caseInsensitive;
160      int defaultIsIndex;      int defaultIsIndex;
161        int defaultIsVariable;
162      int defaultSupportSaved;      int defaultSupportSaved;
163      enum lineType_e entrySeparator;      int defaultIsSaved;
164        int defaultIsUnquoted;
165        enum lineType_e entryStart;
166        enum lineType_e entryEnd;
167      int needsBootPrefix;      int needsBootPrefix;
168      int argsInQuotes;      int argsInQuotes;
169      int maxTitleLength;      int maxTitleLength;
170      int titleBracketed;      int titleBracketed;
171        int titlePosition;
172      int mbHyperFirst;      int mbHyperFirst;
173      int mbInitRdIsModule;      int mbInitRdIsModule;
174      int mbConcatArgs;      int mbConcatArgs;
175      int mbAllowExtraInitRds;      int mbAllowExtraInitRds;
176        char *envFile;
177  };  };
178    
179  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 138  struct keywordTypes grubKeywords[] = { Line 188  struct keywordTypes grubKeywords[] = {
188      { NULL,    0, 0 },      { NULL,    0, 0 },
189  };  };
190    
191    const char *grubFindConfig(struct configFileInfo *cfi) {
192        static const char *configFiles[] = {
193     "/boot/grub/grub.conf",
194     "/boot/grub/menu.lst",
195     "/etc/grub.conf",
196     "/boot/grub2/grub.cfg",
197     "/boot/grub2-efi/grub.cfg",
198     NULL
199        };
200        static int i = -1;
201    
202        if (i == -1) {
203     for (i = 0; configFiles[i] != NULL; i++) {
204        dbgPrintf("Checking \"%s\": ", configFiles[i]);
205        if (!access(configFiles[i], R_OK)) {
206     dbgPrintf("found\n");
207     return configFiles[i];
208        }
209        dbgPrintf("not found\n");
210     }
211        }
212        return configFiles[i];
213    }
214    
215  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
216      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
217      grubKeywords,    /* keywords */      .keywords = grubKeywords,
218      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
219      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
220      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
221      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
222      0,    /* argsInQuotes */      .mbHyperFirst = 1,
223      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
224      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
225      1,                                      /* mbHyperFirst */  };
226      1,                                      /* mbInitRdIsModule */  
227      0,                                      /* mbConcatArgs */  struct keywordTypes grub2Keywords[] = {
228      1,                                      /* mbAllowExtraInitRds */      { "menuentry",  LT_MENUENTRY,   ' ' },
229        { "}",          LT_ENTRY_END,   ' ' },
230        { "echo",       LT_ECHO,        ' ' },
231        { "set",        LT_SET_VARIABLE,' ', '=' },
232        { "root",       LT_BOOTROOT,    ' ' },
233        { "default",    LT_DEFAULT,     ' ' },
234        { "fallback",   LT_FALLBACK,    ' ' },
235        { "linux",      LT_KERNEL,      ' ' },
236        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
237        { "linux16",    LT_KERNEL_16,   ' ' },
238        { "initrd",     LT_INITRD,      ' ', ' ' },
239        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
240        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
241        { "module",     LT_MBMODULE,    ' ' },
242        { "kernel",     LT_HYPER,       ' ' },
243        { "devicetree", LT_DEVTREE,  ' ' },
244        { NULL, 0, 0 },
245    };
246    
247    const char *grub2FindConfig(struct configFileInfo *cfi) {
248        static const char *configFiles[] = {
249     "/boot/grub/grub-efi.cfg",
250     "/boot/grub/grub.cfg",
251     NULL
252        };
253        static int i = -1;
254        static const char *grub_cfg = "/boot/grub/grub.cfg";
255        int rc = -1;
256    
257        if (i == -1) {
258     for (i = 0; configFiles[i] != NULL; i++) {
259        dbgPrintf("Checking \"%s\": ", configFiles[i]);
260        if ((rc = access(configFiles[i], R_OK))) {
261     if (errno == EACCES) {
262        printf("Unable to access bootloader configuration file "
263           "\"%s\": %m\n", configFiles[i]);
264        exit(1);
265     }
266     continue;
267        } else {
268     dbgPrintf("found\n");
269     return configFiles[i];
270        }
271     }
272        }
273    
274        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
275         * that isn't in grub1, and if it exists, return the config file path
276         * that they use. */
277        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
278     dbgPrintf("found\n");
279     return grub_cfg;
280        }
281    
282        dbgPrintf("not found\n");
283        return configFiles[i];
284    }
285    
286    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
287    static char *grub2GetEnv(struct configFileInfo *info, char *name)
288    {
289        static char buf[1025];
290        char *s = NULL;
291        char *ret = NULL;
292        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
293        int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name);
294    
295        if (rc < 0)
296     return NULL;
297    
298        FILE *f = popen(s, "r");
299        if (!f)
300     goto out;
301    
302        memset(buf, '\0', sizeof (buf));
303        ret = fgets(buf, 1024, f);
304        pclose(f);
305    
306        if (ret) {
307     ret += strlen(name) + 1;
308     ret[strlen(ret) - 1] = '\0';
309        }
310        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
311    out:
312        free(s);
313        return ret;
314    }
315    
316    static int sPopCount(const char *s, const char *c)
317    {
318        int ret = 0;
319        if (!s)
320     return -1;
321        for (int i = 0; s[i] != '\0'; i++)
322     for (int j = 0; c[j] != '\0'; j++)
323        if (s[i] == c[j])
324     ret++;
325        return ret;
326    }
327    
328    static char *shellEscape(const char *s)
329    {
330        int l = strlen(s) + sPopCount(s, "'") * 2;
331    
332        char *ret = calloc(l+1, sizeof (*ret));
333        if (!ret)
334     return NULL;
335        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
336     if (s[i] == '\'')
337        ret[j++] = '\\';
338     ret[j] = s[i];
339        }
340        return ret;
341    }
342    
343    static void unquote(char *s)
344    {
345        int l = strlen(s);
346    
347        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
348     memmove(s, s+1, l-2);
349     s[l-2] = '\0';
350        }
351    }
352    
353    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
354    {
355        char *s = NULL;
356        int rc = 0;
357        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
358    
359        unquote(value);
360        value = shellEscape(value);
361        if (!value)
362        return -1;
363    
364        rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value);
365        free(value);
366        if (rc <0)
367     return -1;
368    
369        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
370        rc = system(s);
371        free(s);
372        return rc;
373    }
374    
375    /* this is a gigantic hack to avoid clobbering grub2 variables... */
376    static int is_special_grub2_variable(const char *name)
377    {
378        if (!strcmp(name,"\"${next_entry}\""))
379     return 1;
380        if (!strcmp(name,"\"${prev_saved_entry}\""))
381     return 1;
382        return 0;
383    }
384    
385    int sizeOfSingleLine(struct singleLine * line) {
386      int count = 0;
387    
388      for (int i = 0; i < line->numElements; i++) {
389        int indentSize = 0;
390    
391        count = count + strlen(line->elements[i].item);
392    
393        indentSize = strlen(line->elements[i].indent);
394        if (indentSize > 0)
395          count = count + indentSize;
396        else
397          /* be extra safe and add room for whitespaces */
398          count = count + 1;
399      }
400    
401      /* room for trailing terminator */
402      count = count + 1;
403    
404      return count;
405    }
406    
407    static int isquote(char q)
408    {
409        if (q == '\'' || q == '\"')
410     return 1;
411        return 0;
412    }
413    
414    static int iskernel(enum lineType_e type) {
415        return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
416    }
417    
418    static int isinitrd(enum lineType_e type) {
419        return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
420    }
421    
422    char *grub2ExtractTitle(struct singleLine * line) {
423        char * current;
424        char * current_indent;
425        int current_len;
426        int current_indent_len;
427        int i;
428    
429        /* bail out if line does not start with menuentry */
430        if (strcmp(line->elements[0].item, "menuentry"))
431          return NULL;
432    
433        i = 1;
434        current = line->elements[i].item;
435        current_len = strlen(current);
436    
437        /* if second word is quoted, strip the quotes and return single word */
438        if (isquote(*current) && isquote(current[current_len - 1])) {
439     char *tmp;
440    
441     tmp = strdup(current);
442     *(tmp + current_len - 1) = '\0';
443     return ++tmp;
444        }
445    
446        /* if no quotes, return second word verbatim */
447        if (!isquote(*current))
448     return current;
449    
450        /* second element start with a quote, so we have to find the element
451         * whose last character is also quote (assuming it's the closing one) */
452        int resultMaxSize;
453        char * result;
454        
455        resultMaxSize = sizeOfSingleLine(line);
456        result = malloc(resultMaxSize);
457        snprintf(result, resultMaxSize, "%s", ++current);
458        
459        i++;
460        for (; i < line->numElements; ++i) {
461     current = line->elements[i].item;
462     current_len = strlen(current);
463     current_indent = line->elements[i].indent;
464     current_indent_len = strlen(current_indent);
465    
466     strncat(result, current_indent, current_indent_len);
467     if (!isquote(current[current_len-1])) {
468        strncat(result, current, current_len);
469     } else {
470        strncat(result, current, current_len - 1);
471        break;
472     }
473        }
474        return result;
475    }
476    
477    struct configFileInfo grub2ConfigType = {
478        .findConfig = grub2FindConfig,
479        .getEnv = grub2GetEnv,
480        .setEnv = grub2SetEnv,
481        .keywords = grub2Keywords,
482        .defaultIsIndex = 1,
483        .defaultSupportSaved = 1,
484        .defaultIsVariable = 1,
485        .entryStart = LT_MENUENTRY,
486        .entryEnd = LT_ENTRY_END,
487        .titlePosition = 1,
488        .needsBootPrefix = 1,
489        .mbHyperFirst = 1,
490        .mbInitRdIsModule = 1,
491        .mbAllowExtraInitRds = 1,
492  };  };
493    
494  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 245  struct keywordTypes extlinuxKeywords[] = Line 582  struct keywordTypes extlinuxKeywords[] =
582      { "initrd",    LT_INITRD,      ' ', ',' },      { "initrd",    LT_INITRD,      ' ', ',' },
583      { "append",    LT_KERNELARGS,  ' ' },      { "append",    LT_KERNELARGS,  ' ' },
584      { "prompt",     LT_UNKNOWN,     ' ' },      { "prompt",     LT_UNKNOWN,     ' ' },
585        { "fdt",        LT_DEVTREE,     ' ' },
586        { "fdtdir",     LT_DEVTREE,     ' ' },
587      { NULL,    0, 0 },      { NULL,    0, 0 },
588  };  };
589  int useextlinuxmenu;  int useextlinuxmenu;
590  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
591      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
592      eliloKeywords,    /* keywords */      .keywords = eliloKeywords,
593      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
594      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
595      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
596      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
     0,                                      /* mbHyperFirst */  
     0,                                      /* mbInitRdIsModule */  
     1,                                      /* mbConcatArgs */  
     0,                                      /* mbAllowExtraInitRds */  
597  };  };
598    
599  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
600      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
601      liloKeywords,    /* keywords */      .keywords = liloKeywords,
602      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
603      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
604      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
     0,                                      /* mbHyperFirst */  
     0,                                      /* mbInitRdIsModule */  
     0,                                      /* mbConcatArgs */  
     0,                                      /* mbAllowExtraInitRds */  
605  };  };
606    
607  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
608      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
609      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
610      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
611      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
612      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
613      1,    /* needsBootPrefix */      .maxTitleLength = 15,
614      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
     0,                                      /* mbHyperFirst */  
     0,                                      /* mbInitRdIsModule */  
     0,                                      /* mbConcatArgs */  
     1,                                      /* mbAllowExtraInitRds */  
615  };  };
616    
617  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
618      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
619      siloKeywords,    /* keywords */      .keywords = siloKeywords,
620      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
621      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
622      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
623      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
     0,                                      /* mbHyperFirst */  
     0,                                      /* mbInitRdIsModule */  
     0,                                      /* mbConcatArgs */  
     0,                                      /* mbAllowExtraInitRds */  
624  };  };
625    
626  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
627      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
628      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
629      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
630      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
631      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     1,                                      /* titleBracketed */  
     0,                                      /* mbHyperFirst */  
     0,                                      /* mbInitRdIsModule */  
     0,                                      /* mbConcatArgs */  
     0,                                      /* mbAllowExtraInitRds */  
632  };  };
633    
634  struct configFileInfo extlinuxConfigType = {  struct configFileInfo extlinuxConfigType = {
635      "/boot/extlinux/extlinux.conf",         /* defaultConfig */      .defaultConfig = "/boot/extlinux/extlinux.conf",
636      extlinuxKeywords,                       /* keywords */      .keywords = extlinuxKeywords,
637      0,                                      /* defaultIsIndex */      .caseInsensitive = 1,
638      0,                                      /* defaultSupportSaved */      .entryStart = LT_TITLE,
639      LT_TITLE,                               /* entrySeparator */      .needsBootPrefix = 1,
640      1,                                      /* needsBootPrefix */      .maxTitleLength = 255,
641      0,                                      /* argsInQuotes */      .mbAllowExtraInitRds = 1,
642      255,                                    /* maxTitleLength */      .defaultIsUnquoted = 1,
     0,                                      /* titleBracketed */  
     0,                                      /* mbHyperFirst */  
     0,                                      /* mbInitRdIsModule */  
     0,                                      /* mbConcatArgs */  
     1,                                      /* mbAllowExtraInitRds */  
643  };  };
644    
645  struct grubConfig {  struct grubConfig {
# Line 356  struct grubConfig { Line 654  struct grubConfig {
654      struct configFileInfo * cfi;      struct configFileInfo * cfi;
655  };  };
656    
657    blkid_cache blkid;
658    
659  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
660  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
661       const char * path, const char * prefix,       const char * path, const char * prefix,
662       int * index);       int * index);
663    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
664          int * index);
665  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
666  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
667  struct singleLine * lineDup(struct singleLine * line);  struct singleLine * lineDup(struct singleLine * line);
# Line 369  static int lineWrite(FILE * out, struct Line 671  static int lineWrite(FILE * out, struct
671  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
672         struct configFileInfo * cfi);         struct configFileInfo * cfi);
673  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
674    static void requote(struct singleLine *line, struct configFileInfo * cfi);
675  static void insertElement(struct singleLine * line,  static void insertElement(struct singleLine * line,
676    const char * item, int insertHere,    const char * item, int insertHere,
677    struct configFileInfo * cfi);    struct configFileInfo * cfi);
# Line 423  static char * sdupprintf(const char *for Line 726  static char * sdupprintf(const char *for
726      return buf;      return buf;
727  }  }
728    
729    static enum lineType_e preferredLineType(enum lineType_e type,
730     struct configFileInfo *cfi) {
731        if (isEfi && cfi == &grub2ConfigType) {
732     switch (type) {
733     case LT_KERNEL:
734        return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
735     case LT_INITRD:
736        return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
737     default:
738        return type;
739     }
740    #if defined(__i386__) || defined(__x86_64__)
741        } else if (cfi == &grub2ConfigType) {
742     switch (type) {
743     case LT_KERNEL:
744        return LT_KERNEL_16;
745     case LT_INITRD:
746        return LT_INITRD_16;
747     default:
748        return type;
749     }
750    #endif
751        }
752        return type;
753    }
754    
755  static struct keywordTypes * getKeywordByType(enum lineType_e type,  static struct keywordTypes * getKeywordByType(enum lineType_e type,
756        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
757      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
     for (kw = cfi->keywords; kw->key; kw++) {  
758   if (kw->type == type)   if (kw->type == type)
759      return kw;      return kw;
760      }      }
761      return NULL;      return NULL;
762  }  }
763    
764  static char * getpathbyspec(char *device) {  static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
765      static blkid_cache blkid;      struct keywordTypes *kt = getKeywordByType(type, cfi);
766        if (kt)
767     return kt->key;
768        return "unknown";
769    }
770    
771    static char * getpathbyspec(char *device) {
772      if (!blkid)      if (!blkid)
773          blkid_get_cache(&blkid, NULL);          blkid_get_cache(&blkid, NULL);
774    
775      return blkid_get_devname(blkid, device, NULL);      return blkid_get_devname(blkid, device, NULL);
776  }  }
777    
778    static char * getuuidbydev(char *device) {
779        if (!blkid)
780     blkid_get_cache(&blkid, NULL);
781    
782        return blkid_get_tag_value(blkid, "UUID", device);
783    }
784    
785  static enum lineType_e getTypeByKeyword(char * keyword,  static enum lineType_e getTypeByKeyword(char * keyword,
786   struct configFileInfo * cfi) {   struct configFileInfo * cfi) {
787      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
788      for (kw = cfi->keywords; kw->key; kw++) {   if (cfi->caseInsensitive) {
789   if (!strcmp(keyword, kw->key))      if (!strcasecmp(keyword, kw->key))
790      return kw->type;                  return kw->type;
791     } else {
792        if (!strcmp(keyword, kw->key))
793            return kw->type;
794     }
795      }      }
796      return LT_UNKNOWN;      return LT_UNKNOWN;
797  }  }
# Line 477  static int isBracketedTitle(struct singl Line 821  static int isBracketedTitle(struct singl
821      return 0;      return 0;
822  }  }
823    
824  static int isEntrySeparator(struct singleLine * line,  static int isEntryStart(struct singleLine * line,
825                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
826      return line->type == cfi->entrySeparator || line->type == LT_OTHER ||      return line->type == cfi->entryStart || line->type == LT_OTHER ||
827   (cfi->titleBracketed && isBracketedTitle(line));   (cfi->titleBracketed && isBracketedTitle(line));
828  }  }
829    
830  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
831  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
832      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
833      char * title;      char * title = NULL;
834      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
835      title++;   title = strdup(line->elements[0].item);
836      *(title + strlen(title) - 1) = '\0';   title++;
837     *(title + strlen(title) - 1) = '\0';
838        } else if (line->type == LT_MENUENTRY)
839     title = strdup(line->elements[1].item);
840        else
841     return NULL;
842      return title;      return title;
843  }  }
844    
# Line 532  static void lineInit(struct singleLine * Line 881  static void lineInit(struct singleLine *
881  }  }
882    
883  struct singleLine * lineDup(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
     int i;  
884      struct singleLine * newLine = malloc(sizeof(*newLine));      struct singleLine * newLine = malloc(sizeof(*newLine));
885    
886      newLine->indent = strdup(line->indent);      newLine->indent = strdup(line->indent);
# Line 542  struct singleLine * lineDup(struct singl Line 890  struct singleLine * lineDup(struct singl
890      newLine->elements = malloc(sizeof(*newLine->elements) *      newLine->elements = malloc(sizeof(*newLine->elements) *
891         newLine->numElements);         newLine->numElements);
892    
893      for (i = 0; i < newLine->numElements; i++) {      for (int i = 0; i < newLine->numElements; i++) {
894   newLine->elements[i].indent = strdup(line->elements[i].indent);   newLine->elements[i].indent = strdup(line->elements[i].indent);
895   newLine->elements[i].item = strdup(line->elements[i].item);   newLine->elements[i].item = strdup(line->elements[i].item);
896      }      }
# Line 551  struct singleLine * lineDup(struct singl Line 899  struct singleLine * lineDup(struct singl
899  }  }
900    
901  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
     int i;  
   
902      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
903    
904      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
905   free(line->elements[i].item);   free(line->elements[i].item);
906   free(line->elements[i].indent);   free(line->elements[i].indent);
907      }      }
# Line 566  static void lineFree(struct singleLine * Line 912  static void lineFree(struct singleLine *
912    
913  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
914       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
915      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
916    
917      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
918     /* Need to handle this, because we strip the quotes from
919     * menuentry when read it. */
920     if (line->type == LT_MENUENTRY && i == 1) {
921        if(!isquote(*line->elements[i].item))
922     fprintf(out, "\'%s\'", line->elements[i].item);
923        else
924     fprintf(out, "%s", line->elements[i].item);
925        fprintf(out, "%s", line->elements[i].indent);
926    
927        continue;
928     }
929    
930   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
931      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
932    
# Line 664  static int getNextLine(char ** bufPtr, s Line 1020  static int getNextLine(char ** bufPtr, s
1020      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
1021   char * fullLine;   char * fullLine;
1022   int len;   int len;
  int i;  
1023    
1024   len = strlen(line->indent);   len = strlen(line->indent);
1025   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
1026      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
1027     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1028    
# Line 676  static int getNextLine(char ** bufPtr, s Line 1031  static int getNextLine(char ** bufPtr, s
1031   free(line->indent);   free(line->indent);
1032   line->indent = fullLine;   line->indent = fullLine;
1033    
1034   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1035      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1036      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1037      free(line->elements[i].item);      free(line->elements[i].item);
# Line 695  static int getNextLine(char ** bufPtr, s Line 1050  static int getNextLine(char ** bufPtr, s
1050   * elements up more   * elements up more
1051   */   */
1052   if (!isspace(kw->separatorChar)) {   if (!isspace(kw->separatorChar)) {
     int i;  
1053      char indent[2] = "";      char indent[2] = "";
1054      indent[0] = kw->separatorChar;      indent[0] = kw->separatorChar;
1055      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1056   char *p;   char *p;
  int j;  
1057   int numNewElements;   int numNewElements;
1058    
1059   numNewElements = 0;   numNewElements = 0;
# Line 716  static int getNextLine(char ** bufPtr, s Line 1069  static int getNextLine(char ** bufPtr, s
1069      sizeof(*line->elements) * elementsAlloced);      sizeof(*line->elements) * elementsAlloced);
1070   }   }
1071    
1072   for (j = line->numElements; j > i; j--) {   for (int j = line->numElements; j > i; j--) {
1073   line->elements[j + numNewElements] = line->elements[j];   line->elements[j + numNewElements] = line->elements[j];
1074   }   }
1075   line->numElements += numNewElements;   line->numElements += numNewElements;
# Line 729  static int getNextLine(char ** bufPtr, s Line 1082  static int getNextLine(char ** bufPtr, s
1082   break;   break;
1083   }   }
1084    
1085   free(line->elements[i].indent);   line->elements[i + 1].indent = line->elements[i].indent;
1086   line->elements[i].indent = strdup(indent);   line->elements[i].indent = strdup(indent);
1087   *p++ = '\0';   *p++ = '\0';
1088   i++;   i++;
1089   line->elements[i].item = strdup(p);   line->elements[i].item = strdup(p);
  line->elements[i].indent = strdup("");  
  p = line->elements[i].item;  
1090   }   }
1091      }      }
1092   }   }
# Line 745  static int getNextLine(char ** bufPtr, s Line 1096  static int getNextLine(char ** bufPtr, s
1096      return 0;      return 0;
1097  }  }
1098    
1099    static int isnumber(const char *s)
1100    {
1101        int i;
1102        for (i = 0; s[i] != '\0'; i++)
1103     if (s[i] < '0' || s[i] > '9')
1104        return 0;
1105        return i;
1106    }
1107    
1108  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1109        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1110      int in;      int in;
# Line 756  static struct grubConfig * readConfig(co Line 1116  static struct grubConfig * readConfig(co
1116      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1117      char * end;      char * end;
1118      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1119      int i, len;      int len;
1120      char * buf;      char * buf;
1121    
1122      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1123            printf("Could not find bootloader configuration\n");
1124            exit(1);
1125        } else if (!strcmp(inName, "-")) {
1126   in = 0;   in = 0;
1127      } else {      } else {
1128   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 802  static struct grubConfig * readConfig(co Line 1165  static struct grubConfig * readConfig(co
1165      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1166   }   }
1167    
1168   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1169      sawEntry = 1;      sawEntry = 1;
1170      if (!entry) {      if (!entry) {
1171   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 818  static struct grubConfig * readConfig(co Line 1181  static struct grubConfig * readConfig(co
1181      entry->next = NULL;      entry->next = NULL;
1182   }   }
1183    
1184   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1185      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1186      defaultLine = line;      dbgPrintf("%s", line->indent);
1187        for (int i = 0; i < line->numElements; i++)
1188     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1189        dbgPrintf("\n");
1190        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1191        if (kwType && line->numElements == 3 &&
1192        !strcmp(line->elements[1].item, kwType->key) &&
1193        !is_special_grub2_variable(line->elements[2].item)) {
1194     dbgPrintf("Line sets default config\n");
1195     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1196     defaultLine = line;
1197        }
1198    
1199          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1200      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1201       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1202       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1203       */       */
1204      if (entry->multiboot)      if (entry && entry->multiboot)
1205   line->type = LT_HYPER;   line->type = LT_HYPER;
1206    
1207          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 836  static struct grubConfig * readConfig(co Line 1210  static struct grubConfig * readConfig(co
1210       * This only applies to grub, but that's the only place we       * This only applies to grub, but that's the only place we
1211       * should find LT_MBMODULE lines anyway.       * should find LT_MBMODULE lines anyway.
1212       */       */
1213      struct singleLine * l;      for (struct singleLine *l = entry->lines; l; l = l->next) {
     for (l = entry->lines; l; l = l->next) {  
1214   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1215      break;      break;
1216   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1217      l->type = LT_HYPER;      l->type = LT_HYPER;
1218      break;      break;
1219   }   }
# Line 854  static struct grubConfig * readConfig(co Line 1227  static struct grubConfig * readConfig(co
1227      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1228      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1229    
1230   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1231      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1232        /* make the title/default a single argument (undoing our parsing) */
1233      len = 0;      len = 0;
1234      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1235   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1236   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1237      }      }
1238      buf = malloc(len + 1);      buf = malloc(len + 1);
1239      *buf = '\0';      *buf = '\0';
1240    
1241      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1242   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1243   free(line->elements[i].item);   free(line->elements[i].item);
1244    
# Line 878  static struct grubConfig * readConfig(co Line 1252  static struct grubConfig * readConfig(co
1252      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1253      line->elements[1].item = buf;      line->elements[1].item = buf;
1254      line->numElements = 2;      line->numElements = 2;
1255     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1256        /* let --remove-kernel="TITLE=what" work */
1257        len = 0;
1258        char *extras;
1259        char *title;
1260    
1261        for (int i = 1; i < line->numElements; i++) {
1262     len += strlen(line->elements[i].item);
1263     len += strlen(line->elements[i].indent);
1264        }
1265        buf = malloc(len + 1);
1266        *buf = '\0';
1267    
1268        /* allocate mem for extra flags. */
1269        extras = malloc(len + 1);
1270        *extras = '\0';
1271    
1272        /* get title. */
1273        for (int i = 0; i < line->numElements; i++) {
1274     if (!strcmp(line->elements[i].item, "menuentry"))
1275        continue;
1276     if (isquote(*line->elements[i].item))
1277        title = line->elements[i].item + 1;
1278     else
1279        title = line->elements[i].item;
1280    
1281     len = strlen(title);
1282            if (isquote(title[len-1])) {
1283        strncat(buf, title,len-1);
1284        break;
1285     } else {
1286        strcat(buf, title);
1287        strcat(buf, line->elements[i].indent);
1288     }
1289        }
1290    
1291        /* get extras */
1292        int count = 0;
1293        for (int i = 0; i < line->numElements; i++) {
1294     if (count >= 2) {
1295        strcat(extras, line->elements[i].item);
1296        strcat(extras, line->elements[i].indent);
1297     }
1298    
1299     if (!strcmp(line->elements[i].item, "menuentry"))
1300        continue;
1301    
1302     /* count ' or ", there should be two in menuentry line. */
1303     if (isquote(*line->elements[i].item))
1304        count++;
1305    
1306     len = strlen(line->elements[i].item);
1307    
1308     if (isquote(line->elements[i].item[len -1]))
1309        count++;
1310    
1311     /* ok, we get the final ' or ", others are extras. */
1312                }
1313        line->elements[1].indent =
1314     line->elements[line->numElements - 2].indent;
1315        line->elements[1].item = buf;
1316        line->elements[2].indent =
1317     line->elements[line->numElements - 2].indent;
1318        line->elements[2].item = extras;
1319        line->numElements = 3;
1320   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1321      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1322         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 887  static struct grubConfig * readConfig(co Line 1325  static struct grubConfig * readConfig(co
1325      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1326   int last, len;   int last, len;
1327    
1328   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1329      memmove(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1330      strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1331    
1332   last = line->numElements - 1;   last = line->numElements - 1;
1333   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1334   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1335      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1336      }      }
1337   }   }
1338    
1339     if (line->type == LT_DEFAULT && line->numElements == 2) {
1340        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1341        defaultLine = line;
1342     }
1343    
1344   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1345     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1346     probably responsible for putting new images in the wrong     probably responsible for putting new images in the wrong
# Line 931  static struct grubConfig * readConfig(co Line 1374  static struct grubConfig * readConfig(co
1374   entry->lines = line;   entry->lines = line;
1375      else      else
1376   last->next = line;   last->next = line;
1377      dbgPrintf("readConfig added %d to %p\n", line->type, entry);      dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1378    
1379        /* we could have seen this outside of an entry... if so, we
1380         * ignore it like any other line we don't grok */
1381        if (line->type == LT_ENTRY_END && sawEntry)
1382     sawEntry = 0;
1383   } else {   } else {
1384      if (!cfg->theLines)      if (!cfg->theLines)
1385   cfg->theLines = line;   cfg->theLines = line;
1386      else      else
1387   last->next = line;   last->next = line;
1388      dbgPrintf("readConfig added %d to cfg\n", line->type);      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1389   }   }
1390    
1391   last = line;   last = line;
# Line 945  static struct grubConfig * readConfig(co Line 1393  static struct grubConfig * readConfig(co
1393    
1394      free(incoming);      free(incoming);
1395    
1396        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1397      if (defaultLine) {      if (defaultLine) {
1398   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1399        cfi->defaultSupportSaved &&
1400        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1401     cfg->cfi->defaultIsSaved = 1;
1402     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1403     if (cfg->cfi->getEnv) {
1404        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1405        if (defTitle) {
1406     int index = 0;
1407     if (isnumber(defTitle)) {
1408        index = atoi(defTitle);
1409        entry = findEntryByIndex(cfg, index);
1410     } else {
1411        entry = findEntryByTitle(cfg, defTitle, &index);
1412     }
1413     if (entry)
1414        cfg->defaultImage = index;
1415        }
1416     }
1417     } else if (cfi->defaultIsVariable) {
1418        char *value = defaultLine->elements[2].item;
1419        while (*value && (*value == '"' || *value == '\'' ||
1420        *value == ' ' || *value == '\t'))
1421     value++;
1422        cfg->defaultImage = strtol(value, &end, 10);
1423        while (*end && (*end == '"' || *end == '\'' ||
1424        *end == ' ' || *end == '\t'))
1425     end++;
1426        if (*end) cfg->defaultImage = -1;
1427     } else if (cfi->defaultSupportSaved &&
1428   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1429      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1430   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1431      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1432      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1433   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1434      i = 0;      int i = 0;
1435      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1436   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1437      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 976  static struct grubConfig * readConfig(co Line 1454  static struct grubConfig * readConfig(co
1454          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1455      }      }
1456   }   }
1457        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1458     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1459     if (defTitle) {
1460        int index = 0;
1461        if (isnumber(defTitle)) {
1462     index = atoi(defTitle);
1463     entry = findEntryByIndex(cfg, index);
1464        } else {
1465     entry = findEntryByTitle(cfg, defTitle, &index);
1466        }
1467        if (entry)
1468     cfg->defaultImage = index;
1469     }
1470      } else {      } else {
1471          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1472      }      }
# Line 993  static void writeDefault(FILE * out, cha Line 1484  static void writeDefault(FILE * out, cha
1484    
1485      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1486   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1487      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1488     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1489     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1490        char *title;
1491        entry = findEntryByIndex(cfg, cfg->defaultImage);
1492        line = getLineByType(LT_MENUENTRY, entry->lines);
1493        if (!line)
1494     line = getLineByType(LT_TITLE, entry->lines);
1495        if (line) {
1496     title = extractTitle(line);
1497     if (title)
1498        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1499        }
1500     }
1501        } else if (cfg->defaultImage > -1) {
1502   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1503      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1504      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1505     cfg->defaultImage);
1506        } else {
1507     fprintf(out, "%sdefault%s%d\n", indent, separator,
1508     cfg->defaultImage);
1509        }
1510   } else {   } else {
1511      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1512    
# Line 1048  static int writeConfig(struct grubConfig Line 1558  static int writeConfig(struct grubConfig
1558    
1559      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1560         directory to the dir of the symlink */         directory to the dir of the symlink */
1561              rc = chdir(dirname(strdupa(outName)));      char *dir = strdupa(outName);
1562        rc = chdir(dirname(dir));
1563      do {      do {
1564   buf = alloca(len + 1);   buf = alloca(len + 1);
1565   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1086  static int writeConfig(struct grubConfig Line 1597  static int writeConfig(struct grubConfig
1597      }      }
1598    
1599      line = cfg->theLines;      line = cfg->theLines;
1600        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1601      while (line) {      while (line) {
1602   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1603     line->numElements == 3 &&
1604     !strcmp(line->elements[1].item, defaultKw->key) &&
1605     !is_special_grub2_variable(line->elements[2].item)) {
1606        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1607        needs &= ~MAIN_DEFAULT;
1608     } else if (line->type == LT_DEFAULT) {
1609      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1610      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1611   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 1155  static int numEntries(struct grubConfig Line 1673  static int numEntries(struct grubConfig
1673      return i;      return i;
1674  }  }
1675    
1676    static char *findDiskForRoot()
1677    {
1678        int fd;
1679        char buf[65536];
1680        char *devname;
1681        char *chptr;
1682        int rc;
1683    
1684        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1685            fprintf(stderr, "grubby: failed to open %s: %s\n",
1686                    _PATH_MOUNTED, strerror(errno));
1687            return NULL;
1688        }
1689    
1690        rc = read(fd, buf, sizeof(buf) - 1);
1691        if (rc <= 0) {
1692            fprintf(stderr, "grubby: failed to read %s: %s\n",
1693                    _PATH_MOUNTED, strerror(errno));
1694            close(fd);
1695            return NULL;
1696        }
1697        close(fd);
1698        buf[rc] = '\0';
1699        chptr = buf;
1700    
1701        char *foundanswer = NULL;
1702    
1703        while (chptr && chptr != buf+rc) {
1704            devname = chptr;
1705    
1706            /*
1707             * The first column of a mtab entry is the device, but if the entry is a
1708             * special device it won't start with /, so move on to the next line.
1709             */
1710            if (*devname != '/') {
1711                chptr = strchr(chptr, '\n');
1712                if (chptr)
1713                    chptr++;
1714                continue;
1715            }
1716    
1717            /* Seek to the next space */
1718            chptr = strchr(chptr, ' ');
1719            if (!chptr) {
1720                fprintf(stderr, "grubby: error parsing %s: %s\n",
1721                        _PATH_MOUNTED, strerror(errno));
1722                return NULL;
1723            }
1724    
1725            /*
1726             * The second column of a mtab entry is the mount point, we are looking
1727             * for '/' obviously.
1728             */
1729            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1730                /* remember the last / entry in mtab */
1731               foundanswer = devname;
1732            }
1733    
1734            /* Next line */
1735            chptr = strchr(chptr, '\n');
1736            if (chptr)
1737                chptr++;
1738        }
1739    
1740        /* Return the last / entry found */
1741        if (foundanswer) {
1742            chptr = strchr(foundanswer, ' ');
1743            *chptr = '\0';
1744            return strdup(foundanswer);
1745        }
1746    
1747        return NULL;
1748    }
1749    
1750    void printEntry(struct singleEntry * entry, FILE *f) {
1751        int i;
1752        struct singleLine * line;
1753    
1754        for (line = entry->lines; line; line = line->next) {
1755     log_message(f, "DBG: %s", line->indent);
1756     for (i = 0; i < line->numElements; i++) {
1757        /* Need to handle this, because we strip the quotes from
1758         * menuentry when read it. */
1759        if (line->type == LT_MENUENTRY && i == 1) {
1760     if(!isquote(*line->elements[i].item))
1761        log_message(f, "\'%s\'", line->elements[i].item);
1762     else
1763        log_message(f, "%s", line->elements[i].item);
1764     log_message(f, "%s", line->elements[i].indent);
1765    
1766     continue;
1767        }
1768        
1769        log_message(f, "%s%s",
1770        line->elements[i].item, line->elements[i].indent);
1771     }
1772     log_message(f, "\n");
1773        }
1774    }
1775    
1776    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1777    {
1778        static int once;
1779        va_list argp, argq;
1780    
1781        va_start(argp, fmt);
1782    
1783        va_copy(argq, argp);
1784        if (!once) {
1785     log_time(NULL);
1786     log_message(NULL, "command line: %s\n", saved_command_line);
1787        }
1788        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1789        log_vmessage(NULL, fmt, argq);
1790    
1791        printEntry(entry, NULL);
1792        va_end(argq);
1793    
1794        if (!debug) {
1795     once = 1;
1796         va_end(argp);
1797     return;
1798        }
1799    
1800        if (okay) {
1801     va_end(argp);
1802     return;
1803        }
1804    
1805        if (!once)
1806     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1807        once = 1;
1808        fprintf(stderr, "DBG: Image entry failed: ");
1809        vfprintf(stderr, fmt, argp);
1810        printEntry(entry, stderr);
1811        va_end(argp);
1812    }
1813    
1814    #define beginswith(s, c) ((s) && (s)[0] == (c))
1815    
1816    static int endswith(const char *s, char c)
1817    {
1818     int slen;
1819    
1820     if (!s || !s[0])
1821     return 0;
1822     slen = strlen(s) - 1;
1823    
1824     return s[slen] == c;
1825    }
1826    
1827  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1828    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1829      struct singleLine * line;      struct singleLine * line;
1830      char * fullName;      char * fullName;
1831      int i;      int i;
     struct stat sb, sb2;  
1832      char * dev;      char * dev;
1833      char * rootspec;      char * rootspec;
1834        char * rootdev;
1835    
1836      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) {
1837     notSuitablePrintf(entry, 0, "marked to skip\n");
1838     return 0;
1839        }
1840    
1841      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1842      if (!line || line->numElements < 2) return 0;      if (!line) {
1843     notSuitablePrintf(entry, 0, "no line found\n");
1844     return 0;
1845        }
1846        if (line->numElements < 2) {
1847     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1848        line->numElements);
1849     return 0;
1850        }
1851    
1852      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1853        notSuitablePrintf(entry, 1, "\n");
1854        return 1;
1855        }
1856    
1857      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1858        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1859      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1860      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1861              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));      int hasslash = endswith(bootPrefix, '/') ||
1862      if (access(fullName, R_OK)) return 0;       beginswith(line->elements[1].item + rootspec_offset, '/');
1863        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1864                line->elements[1].item + rootspec_offset);
1865        if (access(fullName, R_OK)) {
1866     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1867     return 0;
1868        }
1869      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1870   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1871      if (i < line->numElements) {      if (i < line->numElements) {
# Line 1195  int suitableImage(struct singleEntry * e Line 1883  int suitableImage(struct singleEntry * e
1883      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1884    
1885              /* failed to find one */              /* failed to find one */
1886              if (!line) return 0;              if (!line) {
1887     notSuitablePrintf(entry, 0, "no line found\n");
1888     return 0;
1889                }
1890    
1891      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1892          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1893      if (i < line->numElements)      if (i < line->numElements)
1894          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1895      else {      else {
1896     notSuitablePrintf(entry, 0, "no root= entry found\n");
1897   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1898          return 0;          return 0;
1899              }              }
# Line 1209  int suitableImage(struct singleEntry * e Line 1901  int suitableImage(struct singleEntry * e
1901      }      }
1902    
1903      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1904      if (!dev)      if (!getpathbyspec(dev)) {
1905            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1906          return 0;          return 0;
1907        } else
1908     dev = getpathbyspec(dev);
1909    
1910      i = stat(dev, &sb);      rootdev = findDiskForRoot();
1911      if (i)      if (!rootdev) {
1912            notSuitablePrintf(entry, 0, "can't find root device\n");
1913   return 0;   return 0;
1914        }
1915    
1916      stat("/", &sb2);      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1917            notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1918     getuuidbydev(rootdev), getuuidbydev(dev));
1919            free(rootdev);
1920            return 0;
1921        }
1922    
1923      if (sb.st_rdev != sb2.st_dev)      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1924            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1925     getuuidbydev(rootdev), getuuidbydev(dev));
1926     free(rootdev);
1927          return 0;          return 0;
1928        }
1929    
1930        free(rootdev);
1931        notSuitablePrintf(entry, 1, "\n");
1932    
1933      return 1;      return 1;
1934  }  }
# Line 1253  struct singleEntry * findEntryByPath(str Line 1962  struct singleEntry * findEntryByPath(str
1962   }   }
1963    
1964   indexVars[i + 1] = -1;   indexVars[i + 1] = -1;
1965    
1966   i = 0;   i = 0;
1967   if (index) {   if (index) {
1968      while (i < *index) i++;      while (i < *index) {
1969      if (indexVars[i] == -1) return NULL;   i++;
1970     if (indexVars[i] == -1) return NULL;
1971        }
1972   }   }
1973    
1974   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1975   if (!entry) return NULL;   if (!entry) return NULL;
1976    
1977   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1978   if (!line) return NULL;   if (!line) return NULL;
1979    
1980   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1301  struct singleEntry * findEntryByPath(str Line 2012  struct singleEntry * findEntryByPath(str
2012    
2013   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
2014      prefix = "";      prefix = "";
2015      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
2016      kernel += 6;      kernel += 6;
2017   }   }
2018    
# Line 1312  struct singleEntry * findEntryByPath(str Line 2023  struct singleEntry * findEntryByPath(str
2023    
2024      /* check all the lines matching checkType */      /* check all the lines matching checkType */
2025      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2026   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
2027       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
2028       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2029   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
2030        ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2031     line = getLineByType(ct, line);
2032     if (!line)
2033        break;  /* not found in this entry */
2034    
2035   if (line && line->numElements >= 2) {   if (line && line->type != LT_MENUENTRY &&
2036     line->numElements >= 2) {
2037      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
2038      if (!strcmp(line->elements[1].item +      if (!strcmp(line->elements[1].item +
2039   ((rootspec != NULL) ? strlen(rootspec) : 0),   ((rootspec != NULL) ? strlen(rootspec) : 0),
2040   kernel + strlen(prefix)))   kernel + strlen(prefix)))
2041   break;   break;
2042   }   }
2043     if(line->type == LT_MENUENTRY &&
2044     !strcmp(line->elements[1].item, kernel))
2045        break;
2046      }      }
2047    
2048      /* make sure this entry has a kernel identifier; this skips      /* make sure this entry has a kernel identifier; this skips
2049       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2050       * unfortunate)       * unfortunate)
2051       */       */
2052      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2053   break; /* found 'im! */   break; /* found 'im! */
2054   }   }
2055    
# Line 1340  struct singleEntry * findEntryByPath(str Line 2059  struct singleEntry * findEntryByPath(str
2059      return entry;      return entry;
2060  }  }
2061    
2062    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2063          int * index) {
2064        struct singleEntry * entry;
2065        struct singleLine * line;
2066        int i;
2067        char * newtitle;
2068    
2069        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2070     if (index && i < *index)
2071        continue;
2072     line = getLineByType(LT_TITLE, entry->lines);
2073     if (!line)
2074        line = getLineByType(LT_MENUENTRY, entry->lines);
2075     if (!line)
2076        continue;
2077     newtitle = grub2ExtractTitle(line);
2078     if (!newtitle)
2079        continue;
2080     if (!strcmp(title, newtitle))
2081        break;
2082        }
2083    
2084        if (!entry)
2085     return NULL;
2086    
2087        if (index)
2088     *index = i;
2089        return entry;
2090    }
2091    
2092  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2093      struct singleEntry * entry;      struct singleEntry * entry;
2094    
# Line 1362  struct singleEntry * findTemplate(struct Line 2111  struct singleEntry * findTemplate(struct
2111      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2112      int index;      int index;
2113    
2114      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2115     if (cfg->cfi->getEnv) {
2116        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2117        if (defTitle) {
2118     int index = 0;
2119     if (isnumber(defTitle)) {
2120        index = atoi(defTitle);
2121        entry = findEntryByIndex(cfg, index);
2122     } else {
2123        entry = findEntryByTitle(cfg, defTitle, &index);
2124     }
2125     if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2126        cfg->defaultImage = index;
2127        if (indexPtr)
2128     *indexPtr = index;
2129        return entry;
2130     }
2131        }
2132     }
2133        } else if (cfg->defaultImage > -1) {
2134   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2135   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2136      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1415  void markRemovedImage(struct grubConfig Line 2183  void markRemovedImage(struct grubConfig
2183        const char * prefix) {        const char * prefix) {
2184      struct singleEntry * entry;      struct singleEntry * entry;
2185    
2186      if (!image) return;      if (!image)
2187     return;
2188    
2189        /* check and see if we're removing the default image */
2190        if (isdigit(*image)) {
2191     entry = findEntryByPath(cfg, image, prefix, NULL);
2192     if(entry)
2193        entry->skip = 1;
2194     return;
2195        }
2196    
2197      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2198   entry->skip = 1;   entry->skip = 1;
# Line 1423  void markRemovedImage(struct grubConfig Line 2200  void markRemovedImage(struct grubConfig
2200    
2201  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2202       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2203       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2204      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2205      int i, j;      int i, j;
2206    
2207      if (newIsDefault) {      if (newIsDefault) {
2208   config->defaultImage = 0;   config->defaultImage = 0;
2209   return;   return;
2210        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2211     if (findEntryByIndex(config, index))
2212        config->defaultImage = index;
2213     else
2214        config->defaultImage = -1;
2215     return;
2216      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2217   i = 0;   i = 0;
2218   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1442  void setDefaultImage(struct grubConfig * Line 2225  void setDefaultImage(struct grubConfig *
2225    
2226      /* 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
2227         changes */         changes */
2228      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2229     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2230        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2231        return;        return;
2232    
# Line 1500  void displayEntry(struct singleEntry * e Line 2284  void displayEntry(struct singleEntry * e
2284      struct singleLine * line;      struct singleLine * line;
2285      char * root = NULL;      char * root = NULL;
2286      int i;      int i;
2287        int j;
2288    
2289        printf("index=%d\n", index);
2290    
2291        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2292        if (!line) {
2293            printf("non linux entry\n");
2294            return;
2295        }
2296    
2297        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2298     printf("kernel=%s\n", line->elements[1].item);
2299        else
2300     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2301    
2302        if (line->numElements >= 3) {
2303     printf("args=\"");
2304     i = 2;
2305     while (i < line->numElements) {
2306        if (!strncmp(line->elements[i].item, "root=", 5)) {
2307     root = line->elements[i].item + 5;
2308        } else {
2309     printf("%s%s", line->elements[i].item,
2310           line->elements[i].indent);
2311        }
2312    
2313        i++;
2314     }
2315     printf("\"\n");
2316        } else {
2317     line = getLineByType(LT_KERNELARGS, entry->lines);
2318     if (line) {
2319        char * s;
2320    
2321        printf("args=\"");
2322        i = 1;
2323        while (i < line->numElements) {
2324     if (!strncmp(line->elements[i].item, "root=", 5)) {
2325        root = line->elements[i].item + 5;
2326     } else {
2327        s = line->elements[i].item;
2328    
2329        printf("%s%s", s, line->elements[i].indent);
2330     }
2331    
2332     i++;
2333        }
2334    
2335        s = line->elements[i - 1].indent;
2336        printf("\"\n");
2337     }
2338        }
2339    
2340        if (!root) {
2341     line = getLineByType(LT_ROOT, entry->lines);
2342     if (line && line->numElements >= 2)
2343        root=line->elements[1].item;
2344        }
2345    
2346        if (root) {
2347     char * s = alloca(strlen(root) + 1);
2348    
2349     strcpy(s, root);
2350     if (s[strlen(s) - 1] == '"')
2351        s[strlen(s) - 1] = '\0';
2352     /* make sure the root doesn't have a trailing " */
2353     printf("root=%s\n", s);
2354        }
2355    
2356        line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2357    
2358        if (line && line->numElements >= 2) {
2359     if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2360        printf("initrd=");
2361     else
2362        printf("initrd=%s", prefix);
2363    
2364     for (i = 1; i < line->numElements; i++)
2365        printf("%s%s", line->elements[i].item, line->elements[i].indent);
2366     printf("\n");
2367        }
2368    
2369        line = getLineByType(LT_TITLE, entry->lines);
2370        if (line) {
2371     printf("title=%s\n", line->elements[1].item);
2372        } else {
2373     char * title;
2374     line = getLineByType(LT_MENUENTRY, entry->lines);
2375     if (line) {
2376        title = grub2ExtractTitle(line);
2377        if (title)
2378     printf("title=%s\n", title);
2379     }
2380        }
2381    
2382        for (j = 0, line = entry->lines; line; line = line->next) {
2383     if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
2384        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2385     printf("mbmodule%d=", j);
2386        else
2387     printf("mbmodule%d=%s", j, prefix);
2388    
2389        for (i = 1; i < line->numElements; i++)
2390     printf("%s%s", line->elements[i].item, line->elements[i].indent);
2391        printf("\n");
2392        j++;
2393     }
2394        }
2395    }
2396    
2397    int isSuseSystem(void) {
2398        const char * path;
2399        const static char default_path[] = "/etc/SuSE-release";
2400    
2401        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2402     path = default_path;
2403    
2404        if (!access(path, R_OK))
2405     return 1;
2406        return 0;
2407    }
2408    
2409    int isSuseGrubConf(const char * path) {
2410        FILE * grubConf;
2411        char * line = NULL;
2412        size_t len = 0, res = 0;
2413    
2414        grubConf = fopen(path, "r");
2415        if (!grubConf) {
2416            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2417     return 0;
2418        }
2419    
2420        while ((res = getline(&line, &len, grubConf)) != -1) {
2421     if (!strncmp(line, "setup", 5)) {
2422        fclose(grubConf);
2423        free(line);
2424        return 1;
2425     }
2426        }
2427    
2428        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2429          path);
2430    
2431        fclose(grubConf);
2432        free(line);
2433        return 0;
2434    }
2435    
2436    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2437        FILE * grubConf;
2438        char * line = NULL;
2439        size_t res = 0, len = 0;
2440    
2441        if (!path) return 1;
2442        if (!lbaPtr) return 1;
2443    
2444        grubConf = fopen(path, "r");
2445        if (!grubConf) return 1;
2446    
2447        while ((res = getline(&line, &len, grubConf)) != -1) {
2448     if (line[res - 1] == '\n')
2449        line[res - 1] = '\0';
2450     else if (len > res)
2451        line[res] = '\0';
2452     else {
2453        line = realloc(line, res + 1);
2454        line[res] = '\0';
2455     }
2456    
2457     if (!strncmp(line, "setup", 5)) {
2458        if (strstr(line, "--force-lba")) {
2459            *lbaPtr = 1;
2460        } else {
2461            *lbaPtr = 0;
2462        }
2463        dbgPrintf("lba: %i\n", *lbaPtr);
2464        break;
2465     }
2466        }
2467    
2468        free(line);
2469        fclose(grubConf);
2470        return 0;
2471    }
2472    
2473    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2474        FILE * grubConf;
2475        char * line = NULL;
2476        size_t res = 0, len = 0;
2477        char * lastParamPtr = NULL;
2478        char * secLastParamPtr = NULL;
2479        char installDeviceNumber = '\0';
2480        char * bounds = NULL;
2481    
2482        if (!path) return 1;
2483        if (!devicePtr) return 1;
2484    
2485        grubConf = fopen(path, "r");
2486        if (!grubConf) return 1;
2487    
2488        while ((res = getline(&line, &len, grubConf)) != -1) {
2489     if (strncmp(line, "setup", 5))
2490        continue;
2491    
2492     if (line[res - 1] == '\n')
2493        line[res - 1] = '\0';
2494     else if (len > res)
2495        line[res] = '\0';
2496     else {
2497        line = realloc(line, res + 1);
2498        line[res] = '\0';
2499     }
2500    
2501     lastParamPtr = bounds = line + res;
2502    
2503     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2504     while (!isspace(*lastParamPtr))
2505        lastParamPtr--;
2506     lastParamPtr++;
2507    
2508     secLastParamPtr = lastParamPtr - 2;
2509     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2510    
2511     if (lastParamPtr + 3 > bounds) {
2512        dbgPrintf("lastParamPtr going over boundary");
2513        fclose(grubConf);
2514        free(line);
2515        return 1;
2516     }
2517     if (!strncmp(lastParamPtr, "(hd", 3))
2518        lastParamPtr += 3;
2519     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2520    
2521     /*
2522     * Second last parameter will decide wether last parameter is
2523     * an IMAGE_DEVICE or INSTALL_DEVICE
2524     */
2525     while (!isspace(*secLastParamPtr))
2526        secLastParamPtr--;
2527     secLastParamPtr++;
2528    
2529     if (secLastParamPtr + 3 > bounds) {
2530        dbgPrintf("secLastParamPtr going over boundary");
2531        fclose(grubConf);
2532        free(line);
2533        return 1;
2534     }
2535     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2536     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2537        secLastParamPtr += 3;
2538        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2539        installDeviceNumber = *secLastParamPtr;
2540     } else {
2541        installDeviceNumber = *lastParamPtr;
2542     }
2543    
2544     *devicePtr = malloc(6);
2545     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2546     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2547     fclose(grubConf);
2548     free(line);
2549     return 0;
2550        }
2551    
2552        free(line);
2553        fclose(grubConf);
2554        return 1;
2555    }
2556    
2557    int grubGetBootFromDeviceMap(const char * device,
2558         char ** bootPtr) {
2559        FILE * deviceMap;
2560        char * line = NULL;
2561        size_t res = 0, len = 0;
2562        char * devicePtr;
2563        char * bounds = NULL;
2564        const char * path;
2565        const static char default_path[] = "/boot/grub/device.map";
2566    
2567        if (!device) return 1;
2568        if (!bootPtr) return 1;
2569    
2570        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2571     path = default_path;
2572    
2573        dbgPrintf("opening grub device.map file from: %s\n", path);
2574        deviceMap = fopen(path, "r");
2575        if (!deviceMap)
2576     return 1;
2577    
2578        while ((res = getline(&line, &len, deviceMap)) != -1) {
2579            if (!strncmp(line, "#", 1))
2580        continue;
2581    
2582      printf("index=%d\n", index);   if (line[res - 1] == '\n')
2583        line[res - 1] = '\0';
2584     else if (len > res)
2585        line[res] = '\0';
2586     else {
2587        line = realloc(line, res + 1);
2588        line[res] = '\0';
2589     }
2590    
2591     devicePtr = line;
2592     bounds = line + res;
2593    
2594     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2595        devicePtr++;
2596     dbgPrintf("device: %s\n", devicePtr);
2597    
2598     if (!strncmp(devicePtr, device, strlen(device))) {
2599        devicePtr += strlen(device);
2600        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2601            devicePtr++;
2602    
2603      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      *bootPtr = strdup(devicePtr);
2604      if (!line) {      break;
2605          printf("non linux entry\n");   }
         return;  
2606      }      }
2607    
2608      printf("kernel=%s\n", line->elements[1].item);      free(line);
2609        fclose(deviceMap);
2610        return 0;
2611    }
2612    
2613      if (line->numElements >= 3) {  int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2614   printf("args=\"");      char * grubDevice;
  i = 2;  
  while (i < line->numElements) {  
     if (!strncmp(line->elements[i].item, "root=", 5)) {  
  root = line->elements[i].item + 5;  
     } else {  
  printf("%s%s", line->elements[i].item,  
        line->elements[i].indent);  
     }  
2615    
2616      i++;      if (suseGrubConfGetInstallDevice(path, &grubDevice))
2617   }   dbgPrintf("error looking for grub installation device\n");
2618   printf("\"\n");      else
2619      } else {   dbgPrintf("grubby installation device: %s\n", grubDevice);
  line = getLineByType(LT_KERNELARGS, entry->lines);  
  if (line) {  
     char * s;  
2620    
2621      printf("args=\"");      if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2622      i = 1;   dbgPrintf("error looking for grub boot device\n");
2623      while (i < line->numElements) {      else
2624   if (!strncmp(line->elements[i].item, "root=", 5)) {   dbgPrintf("grubby boot device: %s\n", *bootPtr);
     root = line->elements[i].item + 5;  
  } else {  
     s = line->elements[i].item;  
2625    
2626      printf("%s%s", s, line->elements[i].indent);      free(grubDevice);
2627   }      return 0;
2628    }
2629    
2630   i++;  int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2631      }      /*
2632         * This SuSE grub configuration file at this location is not your average
2633         * grub configuration file, but instead the grub commands used to setup
2634         * grub on that system.
2635         */
2636        const char * path;
2637        const static char default_path[] = "/etc/grub.conf";
2638    
2639      s = line->elements[i - 1].indent;      if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2640      printf("\"\n");   path = default_path;
  }  
     }  
2641    
2642      if (!root) {      if (!isSuseGrubConf(path)) return 1;
  line = getLineByType(LT_ROOT, entry->lines);  
  if (line && line->numElements >= 2)  
     root=line->elements[1].item;  
     }  
2643    
2644      if (root) {      if (lbaPtr) {
2645   char * s = alloca(strlen(root) + 1);          *lbaPtr = 0;
2646            if (suseGrubConfGetLba(path, lbaPtr))
2647   strcpy(s, root);              return 1;
  if (s[strlen(s) - 1] == '"')  
     s[strlen(s) - 1] = '\0';  
  /* make sure the root doesn't have a trailing " */  
  printf("root=%s\n", s);  
2648      }      }
2649    
2650      line = getLineByType(LT_INITRD, entry->lines);      if (bootPtr) {
2651            *bootPtr = NULL;
2652      if (line && line->numElements >= 2) {          suseGrubConfGetBoot(path, bootPtr);
  printf("initrd=%s", prefix);  
  for (i = 1; i < line->numElements; i++)  
     printf("%s%s", line->elements[i].item, line->elements[i].indent);  
  printf("\n");  
2653      }      }
2654    
2655        return 0;
2656  }  }
2657    
2658  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1582  int parseSysconfigGrub(int * lbaPtr, cha Line 2662  int parseSysconfigGrub(int * lbaPtr, cha
2662      char * start;      char * start;
2663      char * param;      char * param;
2664    
2665      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2666      if (!in) return 1;      if (!in) return 1;
2667    
2668      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1623  int parseSysconfigGrub(int * lbaPtr, cha Line 2703  int parseSysconfigGrub(int * lbaPtr, cha
2703  }  }
2704    
2705  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2706      char * boot;      char * boot = NULL;
2707      int lba;      int lba;
2708    
2709      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2710   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2711   if (boot) printf("boot=%s\n", boot);      free(boot);
2712        return;
2713     }
2714        } else {
2715            if (parseSysconfigGrub(&lba, &boot)) {
2716        free(boot);
2717        return;
2718     }
2719        }
2720    
2721        if (lba) printf("lba\n");
2722        if (boot) {
2723     printf("boot=%s\n", boot);
2724     free(boot);
2725      }      }
2726  }  }
2727    
# Line 1644  int displayInfo(struct grubConfig * conf Line 2737  int displayInfo(struct grubConfig * conf
2737   return 1;   return 1;
2738      }      }
2739    
2740      /* 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
2741         be a better way */         be a better way */
2742      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2743   dumpSysconfigGrub();   dumpSysconfigGrub();
# Line 1677  struct singleLine * addLineTmpl(struct s Line 2770  struct singleLine * addLineTmpl(struct s
2770  {  {
2771      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2772    
2773        if (isEfi && cfi == &grub2ConfigType) {
2774     enum lineType_e old = newLine->type;
2775     newLine->type = preferredLineType(newLine->type, cfi);
2776     if (old != newLine->type)
2777        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2778        }
2779    
2780      if (val) {      if (val) {
2781   /* override the inherited value with our own.   /* override the inherited value with our own.
2782   * This is a little weak because it only applies to elements[1]   * This is a little weak because it only applies to elements[1]
# Line 1686  struct singleLine * addLineTmpl(struct s Line 2786  struct singleLine * addLineTmpl(struct s
2786   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2787    
2788   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2789   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2790      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2791      if (rootspec != NULL) {      if (rootspec != NULL) {
2792   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 1723  struct singleLine *  addLine(struct sing Line 2823  struct singleLine *  addLine(struct sing
2823      /* NB: This function shouldn't allocate items on the heap, rather on the      /* NB: This function shouldn't allocate items on the heap, rather on the
2824       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2825       */       */
   
2826      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2827   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2828   tmpl.type = type;   tmpl.type = type;
# Line 1733  struct singleLine *  addLine(struct sing Line 2832  struct singleLine *  addLine(struct sing
2832   sprintf(tmpl.elements[0].item, "[%s]", val);   sprintf(tmpl.elements[0].item, "[%s]", val);
2833   tmpl.elements[0].indent = "";   tmpl.elements[0].indent = "";
2834   val = NULL;   val = NULL;
2835        } else if (type == LT_MENUENTRY) {
2836     char *lineend = "--class gnu-linux --class gnu --class os {";
2837     if (!val) {
2838        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2839        abort();
2840     }
2841     kw = getKeywordByType(type, cfi);
2842     if (!kw) {
2843        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2844        abort();
2845     }
2846     tmpl.indent = "";
2847     tmpl.type = type;
2848     tmpl.numElements = 3;
2849     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2850     tmpl.elements[0].item = kw->key;
2851     tmpl.elements[0].indent = alloca(2);
2852     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2853     tmpl.elements[1].item = (char *)val;
2854     tmpl.elements[1].indent = alloca(2);
2855     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2856     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2857     strcpy(tmpl.elements[2].item, lineend);
2858     tmpl.elements[2].indent = "";
2859      } else {      } else {
2860   kw = getKeywordByType(type, cfi);   kw = getKeywordByType(type, cfi);
2861   if (!kw) abort();   if (!kw) {
2862        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2863        abort();
2864     }
2865   tmpl.type = type;   tmpl.type = type;
2866   tmpl.numElements = val ? 2 : 1;   tmpl.numElements = val ? 2 : 1;
2867   tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);   tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
# Line 1759  struct singleLine *  addLine(struct sing Line 2885  struct singleLine *  addLine(struct sing
2885   if (!line->next && !prev) prev = line;   if (!line->next && !prev) prev = line;
2886      }      }
2887    
2888      if (prev == entry->lines)      struct singleLine *menuEntry;
2889   tmpl.indent = defaultIndent ?: "";      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2890      else      if (tmpl.type == LT_ENTRY_END) {
2891   tmpl.indent = prev->indent;   if (menuEntry)
2892        tmpl.indent = menuEntry->indent;
2893     else
2894        tmpl.indent = defaultIndent ?: "";
2895        } else if (tmpl.type != LT_MENUENTRY) {
2896     if (menuEntry)
2897        tmpl.indent = "\t";
2898     else if (prev == entry->lines)
2899        tmpl.indent = defaultIndent ?: "";
2900     else
2901        tmpl.indent = prev->indent;
2902        }
2903    
2904      return addLineTmpl(entry, &tmpl, prev, val, cfi);      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2905  }  }
# Line 1789  void removeLine(struct singleEntry * ent Line 2926  void removeLine(struct singleEntry * ent
2926      free(line);      free(line);
2927  }  }
2928    
2929    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2930    {
2931        struct singleLine newLine = {
2932     .indent = tmplLine->indent,
2933     .type = tmplLine->type,
2934     .next = tmplLine->next,
2935        };
2936        int firstQuotedItem = -1;
2937        int quoteLen = 0;
2938        int j;
2939        int element = 0;
2940        char *c;
2941    
2942        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2943        strcpy(c, tmplLine->elements[0].item);
2944        insertElement(&newLine, c, element++, cfi);
2945        free(c);
2946        c = NULL;
2947    
2948        for (j = 1; j < tmplLine->numElements; j++) {
2949     if (firstQuotedItem == -1) {
2950        quoteLen += strlen(tmplLine->elements[j].item);
2951        
2952        if (isquote(tmplLine->elements[j].item[0])) {
2953     firstQuotedItem = j;
2954            quoteLen += strlen(tmplLine->elements[j].indent);
2955        } else {
2956     c = malloc(quoteLen + 1);
2957     strcpy(c, tmplLine->elements[j].item);
2958     insertElement(&newLine, c, element++, cfi);
2959     free(c);
2960     quoteLen = 0;
2961        }
2962     } else {
2963        int itemlen = strlen(tmplLine->elements[j].item);
2964        quoteLen += itemlen;
2965        quoteLen += strlen(tmplLine->elements[j].indent);
2966        
2967        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2968     c = malloc(quoteLen + 1);
2969     c[0] = '\0';
2970     for (int i = firstQuotedItem; i < j+1; i++) {
2971        strcat(c, tmplLine->elements[i].item);
2972        strcat(c, tmplLine->elements[i].indent);
2973     }
2974     insertElement(&newLine, c, element++, cfi);
2975     free(c);
2976    
2977     firstQuotedItem = -1;
2978     quoteLen = 0;
2979        }
2980     }
2981        }
2982        while (tmplLine->numElements)
2983     removeElement(tmplLine, 0);
2984        if (tmplLine->elements)
2985     free(tmplLine->elements);
2986    
2987        tmplLine->numElements = newLine.numElements;
2988        tmplLine->elements = newLine.elements;
2989    }
2990    
2991  static void insertElement(struct singleLine * line,  static void insertElement(struct singleLine * line,
2992    const char * item, int insertHere,    const char * item, int insertHere,
2993    struct configFileInfo * cfi)    struct configFileInfo * cfi)
# Line 1895  int updateActualImage(struct grubConfig Line 3094  int updateActualImage(struct grubConfig
3094      const char ** arg;      const char ** arg;
3095      int useKernelArgs, useRoot;      int useKernelArgs, useRoot;
3096      int firstElement;      int firstElement;
3097      int *usedElements, *usedArgs;      int *usedElements;
3098      int doreplace;      int doreplace;
3099    
3100      if (!image) return 0;      if (!image) return 0;
# Line 1930  int updateActualImage(struct grubConfig Line 3129  int updateActualImage(struct grubConfig
3129      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
3130         && !multibootArgs);         && !multibootArgs);
3131    
     for (k = 0, arg = newArgs; *arg; arg++, k++) ;  
     usedArgs = calloc(k, sizeof(*usedArgs));  
   
3132      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3133    
3134   if (multibootArgs && !entry->multiboot)   if (multibootArgs && !entry->multiboot)
# Line 1960  int updateActualImage(struct grubConfig Line 3156  int updateActualImage(struct grubConfig
3156      firstElement = 2;      firstElement = 2;
3157    
3158   } else {   } else {
3159      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3160      if (!line) {      if (!line) {
3161   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3162   continue;   continue;
# Line 2008  int updateActualImage(struct grubConfig Line 3204  int updateActualImage(struct grubConfig
3204          usedElements = calloc(line->numElements, sizeof(*usedElements));          usedElements = calloc(line->numElements, sizeof(*usedElements));
3205    
3206   for (k = 0, arg = newArgs; *arg; arg++, k++) {   for (k = 0, arg = newArgs; *arg; arg++, k++) {
             if (usedArgs[k]) continue;  
3207    
3208      doreplace = 1;      doreplace = 1;
3209      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
# Line 2023  int updateActualImage(struct grubConfig Line 3218  int updateActualImage(struct grubConfig
3218                      continue;                      continue;
3219   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
3220                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
3221      break;      break;
3222                  }                  }
3223              }              }
# Line 2093  int updateActualImage(struct grubConfig Line 3287  int updateActualImage(struct grubConfig
3287   }   }
3288      }      }
3289    
     free(usedArgs);  
3290      free(newArgs);      free(newArgs);
3291      free(oldArgs);      free(oldArgs);
3292    
# Line 2119  int updateImage(struct grubConfig * cfg, Line 3312  int updateImage(struct grubConfig * cfg,
3312      return rc;      return rc;
3313  }  }
3314    
3315    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3316     const char * image, const char * prefix, const char * initrd,
3317     const char * title) {
3318        struct singleEntry * entry;
3319        struct singleLine * line, * kernelLine, *endLine = NULL;
3320        int index = 0;
3321    
3322        if (!image) return 0;
3323    
3324        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3325            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3326            if (!kernelLine) continue;
3327    
3328     /* if title is supplied, the entry's title must match it. */
3329     if (title) {
3330        char *linetitle;
3331    
3332        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3333        if (!line)
3334     continue;
3335    
3336        linetitle = extractTitle(line);
3337        if (!linetitle)
3338     continue;
3339        if (strcmp(title, linetitle)) {
3340     free(linetitle);
3341     continue;
3342        }
3343        free(linetitle);
3344     }
3345    
3346            if (prefix) {
3347                int prefixLen = strlen(prefix);
3348                if (!strncmp(initrd, prefix, prefixLen))
3349                    initrd += prefixLen;
3350            }
3351     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3352     if (endLine)
3353        removeLine(entry, endLine);
3354            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3355     kernelLine->indent, initrd);
3356            if (!line)
3357        return 1;
3358     if (endLine) {
3359        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3360                if (!line)
3361     return 1;
3362     }
3363    
3364            break;
3365        }
3366    
3367        return 0;
3368    }
3369    
3370    int updateInitrd(struct grubConfig * cfg, const char * image,
3371                     const char * prefix, const char * initrd, const char * title) {
3372        struct singleEntry * entry;
3373        struct singleLine * line, * kernelLine, *endLine = NULL;
3374        int index = 0;
3375    
3376        if (!image) return 0;
3377    
3378        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3379            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3380            if (!kernelLine) continue;
3381    
3382     /* if title is supplied, the entry's title must match it. */
3383     if (title) {
3384        char *linetitle;
3385    
3386        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3387        if (!line)
3388     continue;
3389    
3390        linetitle = extractTitle(line);
3391        if (!linetitle)
3392     continue;
3393        if (strcmp(title, linetitle)) {
3394     free(linetitle);
3395     continue;
3396        }
3397        free(linetitle);
3398     }
3399    
3400            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3401            if (line)
3402                removeLine(entry, line);
3403            if (prefix) {
3404                int prefixLen = strlen(prefix);
3405                if (!strncmp(initrd, prefix, prefixLen))
3406                    initrd += prefixLen;
3407            }
3408     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3409     if (endLine)
3410        removeLine(entry, endLine);
3411     enum lineType_e lt;
3412     switch(kernelLine->type) {
3413        case LT_KERNEL:
3414            lt = LT_INITRD;
3415     break;
3416        case LT_KERNEL_EFI:
3417            lt = LT_INITRD_EFI;
3418     break;
3419        case LT_KERNEL_16:
3420            lt = LT_INITRD_16;
3421     break;
3422        default:
3423            lt = preferredLineType(LT_INITRD, cfg->cfi);
3424     }
3425            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3426            if (!line)
3427        return 1;
3428     if (endLine) {
3429        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3430                if (!line)
3431     return 1;
3432     }
3433    
3434            break;
3435        }
3436    
3437        return 0;
3438    }
3439    
3440  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3441      int fd;      int fd;
3442      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 2142  int checkDeviceBootloader(const char * d Line 3460  int checkDeviceBootloader(const char * d
3460      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3461   return 0;   return 0;
3462    
3463      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3464   offset = boot[2] + 2;   offset = boot[2] + 2;
3465      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3466   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3467      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3468   offset = boot[1] + 2;        offset = boot[1] + 2;
3469            /*
3470     * it looks like grub, when copying stage1 into the mbr, patches stage1
3471     * right after the JMP location, replacing other instructions such as
3472     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3473     * different bytes.
3474     */
3475          if ((bootSect[offset + 1] == NOOP_OPCODE)
3476      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3477     offset = offset + 3;
3478          }
3479      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3480   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3481      } else {      } else {
# Line 2289  int checkForLilo(struct grubConfig * con Line 3617  int checkForLilo(struct grubConfig * con
3617      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3618  }  }
3619    
3620    int checkForGrub2(struct grubConfig * config) {
3621        if (!access("/etc/grub.d/", R_OK))
3622     return 2;
3623    
3624        return 1;
3625    }
3626    
3627  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3628      int fd;      int fd;
3629      unsigned char bootSect[512];      unsigned char bootSect[512];
3630      char * boot;      char * boot;
3631        int onSuse = isSuseSystem();
3632    
3633      if (parseSysconfigGrub(NULL, &boot))  
3634   return 0;      if (onSuse) {
3635     if (parseSuseGrubConf(NULL, &boot))
3636        return 0;
3637        } else {
3638     if (parseSysconfigGrub(NULL, &boot))
3639        return 0;
3640        }
3641    
3642      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3643      if (!boot)      if (!boot)
# Line 2314  int checkForGrub(struct grubConfig * con Line 3656  int checkForGrub(struct grubConfig * con
3656      }      }
3657      close(fd);      close(fd);
3658    
3659        /* The more elaborate checks do not work on SuSE. The checks done
3660         * seem to be reasonble (at least for now), so just return success
3661         */
3662        if (onSuse)
3663     return 2;
3664    
3665      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3666  }  }
3667    
# Line 2347  int checkForExtLinux(struct grubConfig * Line 3695  int checkForExtLinux(struct grubConfig *
3695      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3696  }  }
3697    
3698    int checkForYaboot(struct grubConfig * config) {
3699        /*
3700         * This is a simplistic check that we consider good enough for own puporses
3701         *
3702         * If we were to properly check if yaboot is *installed* we'd need to:
3703         * 1) get the system boot device (LT_BOOT)
3704         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3705         *    the content on the boot device
3706         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3707         * 4) check again if binary and boot device contents match
3708         */
3709        if (!access("/etc/yaboot.conf", R_OK))
3710     return 2;
3711    
3712        return 1;
3713    }
3714    
3715    int checkForElilo(struct grubConfig * config) {
3716        if (!access("/etc/elilo.conf", R_OK))
3717     return 2;
3718    
3719        return 1;
3720    }
3721    
3722  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3723      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3724    
# Line 2361  static char * getRootSpecifier(char * st Line 3733  static char * getRootSpecifier(char * st
3733  static char * getInitrdVal(struct grubConfig * config,  static char * getInitrdVal(struct grubConfig * config,
3734     const char * prefix, struct singleLine *tmplLine,     const char * prefix, struct singleLine *tmplLine,
3735     const char * newKernelInitrd,     const char * newKernelInitrd,
3736     char ** extraInitrds, int extraInitrdCount)     const char ** extraInitrds, int extraInitrdCount)
3737  {  {
3738      char *initrdVal, *end;      char *initrdVal, *end;
3739      int i;      int i;
# Line 2406  static char * getInitrdVal(struct grubCo Line 3778  static char * getInitrdVal(struct grubCo
3778    
3779  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3780           const char * prefix,           const char * prefix,
3781   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3782   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3783   char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3784                   char * newMBKernel, char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3785     const char * newDevTreePath) {
3786      struct singleEntry * new;      struct singleEntry * new;
3787      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3788      int needs;      int needs;
# Line 2450  int addNewKernel(struct grubConfig * con Line 3823  int addNewKernel(struct grubConfig * con
3823          needs |= NEED_MB;          needs |= NEED_MB;
3824          new->multiboot = 1;          new->multiboot = 1;
3825      }      }
3826        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3827     needs |= NEED_DEVTREE;
3828    
3829      if (template) {      if (template) {
3830   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 2463  int addNewKernel(struct grubConfig * con Line 3838  int addNewKernel(struct grubConfig * con
3838      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3839      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3840    
3841      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
  tmplLine->numElements >= 2) {  
3842   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3843      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3844       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 2541  int addNewKernel(struct grubConfig * con Line 3915  int addNewKernel(struct grubConfig * con
3915      /* template is multi but new is not,      /* template is multi but new is not,
3916       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3917       */       */
3918      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3919      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3920      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3921   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3922     config->cfi)->key);
3923      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3924    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3925      config->cfi);
3926      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3927   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3928      char *initrdVal;      char *initrdVal;
3929      /* template is multi but new is not,      /* template is multi but new is not,
3930       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3931       */       */
3932      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3933      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3934      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3935   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3936     config->cfi)->key);
3937      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3938      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3939      free(initrdVal);      free(initrdVal);
3940      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3941   }   }
3942    
3943      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3944   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3945      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3946      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 2590  int addNewKernel(struct grubConfig * con Line 3966  int addNewKernel(struct grubConfig * con
3966      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3967   }   }
3968    
3969        } else if (tmplLine->type == LT_MENUENTRY &&
3970           (needs & NEED_TITLE)) {
3971     requote(tmplLine, config->cfi);
3972     char *nkt = malloc(strlen(newKernelTitle)+3);
3973     strcpy(nkt, "'");
3974     strcat(nkt, newKernelTitle);
3975     strcat(nkt, "'");
3976     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3977     free(nkt);
3978     needs &= ~NEED_TITLE;
3979      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3980         (needs & NEED_TITLE)) {         (needs & NEED_TITLE)) {
3981   if (tmplLine->numElements >= 2) {   if (tmplLine->numElements >= 2) {
# Line 2603  int addNewKernel(struct grubConfig * con Line 3989  int addNewKernel(struct grubConfig * con
3989        tmplLine->indent, newKernelTitle);        tmplLine->indent, newKernelTitle);
3990      needs &= ~NEED_TITLE;      needs &= ~NEED_TITLE;
3991   }   }
3992        } else if (tmplLine->type == LT_ECHO) {
3993        requote(tmplLine, config->cfi);
3994        static const char *prefix = "'Loading ";
3995        if (tmplLine->numElements > 1 &&
3996        strstr(tmplLine->elements[1].item, prefix) &&
3997        masterLine->next &&
3998        iskernel(masterLine->next->type)) {
3999     char *newTitle = malloc(strlen(prefix) +
4000     strlen(newKernelTitle) + 2);
4001    
4002     strcpy(newTitle, prefix);
4003     strcat(newTitle, newKernelTitle);
4004     strcat(newTitle, "'");
4005     newLine = addLine(new, config->cfi, LT_ECHO,
4006     tmplLine->indent, newTitle);
4007     free(newTitle);
4008        } else {
4009     /* pass through other lines from the template */
4010     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
4011     config->cfi);
4012        }
4013        } else if (tmplLine->type == LT_DEVTREE &&
4014           tmplLine->numElements == 2 && newDevTreePath) {
4015            newLine = addLineTmpl(new, tmplLine, newLine,
4016          newDevTreePath + strlen(prefix),
4017          config->cfi);
4018     needs &= ~NEED_DEVTREE;
4019        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
4020     const char *ndtp = newDevTreePath;
4021     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
4022        ndtp += strlen(prefix);
4023     newLine = addLine(new, config->cfi, LT_DEVTREE,
4024      config->secondaryIndent,
4025      ndtp);
4026     needs &= ~NEED_DEVTREE;
4027     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4028      } else {      } else {
4029   /* pass through other lines from the template */   /* pass through other lines from the template */
4030   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 2614  int addNewKernel(struct grubConfig * con Line 4035  int addNewKernel(struct grubConfig * con
4035   /* don't have a template, so start the entry with the   /* don't have a template, so start the entry with the
4036   * appropriate starting line   * appropriate starting line
4037   */   */
4038   switch (config->cfi->entrySeparator) {   switch (config->cfi->entryStart) {
4039      case LT_KERNEL:      case LT_KERNEL:
4040        case LT_KERNEL_EFI:
4041        case LT_KERNEL_16:
4042   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
4043      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
4044   } else {   } else {
4045      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
4046              preferredLineType(LT_KERNEL, config->cfi),
4047        config->primaryIndent,        config->primaryIndent,
4048        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
4049      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 2633  int addNewKernel(struct grubConfig * con Line 4057  int addNewKernel(struct grubConfig * con
4057   needs &= ~NEED_MB;   needs &= ~NEED_MB;
4058   break;   break;
4059    
4060        case LT_MENUENTRY: {
4061     char *nkt = malloc(strlen(newKernelTitle)+3);
4062     strcpy(nkt, "'");
4063     strcat(nkt, newKernelTitle);
4064     strcat(nkt, "'");
4065            newLine = addLine(new, config->cfi, LT_MENUENTRY,
4066      config->primaryIndent, nkt);
4067     free(nkt);
4068     needs &= ~NEED_TITLE;
4069     needs |= NEED_END;
4070     break;
4071        }
4072      case LT_TITLE:      case LT_TITLE:
4073   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
4074   char * templabel;   char * templabel;
# Line 2664  int addNewKernel(struct grubConfig * con Line 4100  int addNewKernel(struct grubConfig * con
4100   }   }
4101      }      }
4102    
4103        struct singleLine *endLine = NULL;
4104        endLine = getLineByType(LT_ENTRY_END, new->lines);
4105        if (endLine) {
4106        removeLine(new, endLine);
4107        needs |= NEED_END;
4108        }
4109    
4110      /* add the remainder of the lines, i.e. those that either      /* add the remainder of the lines, i.e. those that either
4111       * weren't present in the template, or in the case of no template,       * weren't present in the template, or in the case of no template,
4112       * all the lines following the entrySeparator.       * all the lines following the entryStart.
4113       */       */
4114      if (needs & NEED_TITLE) {      if (needs & NEED_TITLE) {
4115   newLine = addLine(new, config->cfi, LT_TITLE,   newLine = addLine(new, config->cfi, LT_TITLE,
# Line 2683  int addNewKernel(struct grubConfig * con Line 4126  int addNewKernel(struct grubConfig * con
4126      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
4127   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4128    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4129        config->cfi)) ?        config->cfi))
4130    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
4131     : preferredLineType(LT_KERNEL, config->cfi),
4132    config->secondaryIndent,    config->secondaryIndent,
4133    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
4134   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 2700  int addNewKernel(struct grubConfig * con Line 4144  int addNewKernel(struct grubConfig * con
4144   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4145   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4146    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4147        config->cfi)) ?        config->cfi))
4148    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
4149       : preferredLineType(LT_INITRD, config->cfi),
4150    config->secondaryIndent,    config->secondaryIndent,
4151    initrdVal);    initrdVal);
4152   free(initrdVal);   free(initrdVal);
4153   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4154      }      }
4155        if (needs & NEED_DEVTREE) {
4156     newLine = addLine(new, config->cfi, LT_DEVTREE,
4157      config->secondaryIndent,
4158      newDevTreePath);
4159     needs &= ~NEED_DEVTREE;
4160        }
4161    
4162        /* NEEDS_END must be last on bootloaders that need it... */
4163        if (needs & NEED_END) {
4164     newLine = addLine(new, config->cfi, LT_ENTRY_END,
4165     config->secondaryIndent, NULL);
4166     needs &= ~NEED_END;
4167        }
4168    
4169      if (needs) {      if (needs) {
4170   printf(_("grubby: needs=%d, aborting\n"), needs);   printf(_("grubby: needs=%d, aborting\n"), needs);
# Line 2728  static void traceback(int signum) Line 4186  static void traceback(int signum)
4186      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
4187      size = backtrace(array, 40);      size = backtrace(array, 40);
4188    
4189      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4190              (unsigned long)size);              (unsigned long)size);
4191      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
4192      exit(1);      exit(1);
# Line 2736  static void traceback(int signum) Line 4194  static void traceback(int signum)
4194    
4195  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4196      poptContext optCon;      poptContext optCon;
4197      char * grubConfig = NULL;      const char * grubConfig = NULL;
4198      char * outputFile = NULL;      char * outputFile = NULL;
4199      int arg = 0;      int arg = 0;
4200      int flags = 0;      int flags = 0;
4201      int badImageOkay = 0;      int badImageOkay = 0;
4202        int configureGrub2 = 0;
4203      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4204      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4205      int configureExtLinux = 0;      int configureExtLinux = 0;
# Line 2752  int main(int argc, const char ** argv) { Line 4211  int main(int argc, const char ** argv) {
4211      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4212      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4213      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4214      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4215      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4216      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4217      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 2762  int main(int argc, const char ** argv) { Line 4221  int main(int argc, const char ** argv) {
4221      char * removeArgs = NULL;      char * removeArgs = NULL;
4222      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4223      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4224        char * envPath = NULL;
4225      const char * chptr = NULL;      const char * chptr = NULL;
4226      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4227      struct grubConfig * config;      struct grubConfig * config;
4228      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4229      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4230      int displayDefault = 0;      int displayDefault = 0;
4231        int displayDefaultIndex = 0;
4232        int displayDefaultTitle = 0;
4233        int defaultIndex = -1;
4234      struct poptOption options[] = {      struct poptOption options[] = {
4235   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4236      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2785  int main(int argc, const char ** argv) { Line 4248  int main(int argc, const char ** argv) {
4248   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4249      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4250      _("bootfs") },      _("bootfs") },
4251  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4252   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4253      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4254  #endif  #endif
4255   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4256      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 2798  int main(int argc, const char ** argv) { Line 4261  int main(int argc, const char ** argv) {
4261        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4262        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4263        "template"), NULL },        "template"), NULL },
4264     { "debug", 0, 0, &debug, 0,
4265        _("print debugging information for failures") },
4266   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4267      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4268     { "default-index", 0, 0, &displayDefaultIndex, 0,
4269        _("display the index of the default kernel") },
4270     { "default-title", 0, 0, &displayDefaultTitle, 0,
4271        _("display the title of the default kernel") },
4272     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4273        _("device tree file for new stanza"), _("dtb-path") },
4274     { "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4275        _("device tree directory for new stanza"), _("dtb-path") },
4276   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4277      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4278     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4279        _("force grub2 stanzas to use efi") },
4280     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4281        _("path for environment data"),
4282        _("path") },
4283   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4284      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4285   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4286      _("configure grub bootloader") },      _("configure grub bootloader") },
4287     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4288        _("configure grub2 bootloader") },
4289   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4290      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4291      _("kernel-path") },      _("kernel-path") },
4292   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4293      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4294   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4295      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4296   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4297      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4298   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2832  int main(int argc, const char ** argv) { Line 4312  int main(int argc, const char ** argv) {
4312   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4313      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4314        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4315     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4316        _("make the given entry index the default entry"),
4317        _("entry-index") },
4318   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4319      _("configure silo bootloader") },      _("configure silo bootloader") },
4320   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2853  int main(int argc, const char ** argv) { Line 4336  int main(int argc, const char ** argv) {
4336    
4337      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4338    
4339        int i = 0;
4340        for (int j = 1; j < argc; j++)
4341     i += strlen(argv[j]) + 1;
4342        saved_command_line = malloc(i);
4343        if (!saved_command_line) {
4344     fprintf(stderr, "grubby: %m\n");
4345     exit(1);
4346        }
4347        saved_command_line[0] = '\0';
4348        for (int j = 1; j < argc; j++) {
4349     strcat(saved_command_line, argv[j]);
4350     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4351        }
4352    
4353      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4354      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4355    
# Line 2885  int main(int argc, const char ** argv) { Line 4382  int main(int argc, const char ** argv) {
4382   return 1;   return 1;
4383      }      }
4384    
4385      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4386   configureYaboot + configureSilo + configureZipl +   configureYaboot + configureSilo + configureZipl +
4387   configureExtLinux ) > 1) {   configureExtLinux ) > 1) {
4388   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
# Line 2894  int main(int argc, const char ** argv) { Line 4391  int main(int argc, const char ** argv) {
4391   fprintf(stderr,   fprintf(stderr,
4392      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4393   return 1;   return 1;
4394        } else if (configureGrub2) {
4395     cfi = &grub2ConfigType;
4396     if (envPath)
4397        cfi->envFile = envPath;
4398      } else if (configureLilo) {      } else if (configureLilo) {
4399   cfi = &liloConfigType;   cfi = &liloConfigType;
4400      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2912  int main(int argc, const char ** argv) { Line 4413  int main(int argc, const char ** argv) {
4413      }      }
4414    
4415      if (!cfi) {      if (!cfi) {
4416            if (grub2FindConfig(&grub2ConfigType))
4417        cfi = &grub2ConfigType;
4418     else
4419        #ifdef __ia64__        #ifdef __ia64__
4420   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4421        #elif __powerpc__        #elif __powerpc__
4422   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4423        #elif __sparc__        #elif __sparc__
4424          cfi = &siloConfigType;              cfi = &siloConfigType;
4425        #elif __s390__        #elif __s390__
4426          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4427        #elif __s390x__        #elif __s390x__
4428          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4429        #else        #else
4430   cfi = &grubConfigType;      cfi = &grubConfigType;
4431        #endif        #endif
4432      }      }
4433    
4434      if (!grubConfig)      if (!grubConfig) {
4435   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4436        grubConfig = cfi->findConfig(cfi);
4437     if (!grubConfig)
4438        grubConfig = cfi->defaultConfig;
4439        }
4440    
4441      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4442    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4443    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4444        (defaultIndex >= 0))) {
4445   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4446    "specified option"));    "specified option"));
4447   return 1;   return 1;
4448      }      }
4449    
4450      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4451     removeKernelPath)) {     removeKernelPath)) {
4452   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4453    "be used when adding or removing kernels\n"));    "be used when adding or removing kernels\n"));
# Line 2948  int main(int argc, const char ** argv) { Line 4457  int main(int argc, const char ** argv) {
4457      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4458   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4459   return 1;   return 1;
4460      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (copyDefault ||
4461    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4462    makeDefault || extraInitrdCount > 0)) {    makeDefault || extraInitrdCount > 0)) {
4463   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4464   return 1;   return 1;
# Line 2974  int main(int argc, const char ** argv) { Line 4483  int main(int argc, const char ** argv) {
4483   makeDefault = 1;   makeDefault = 1;
4484   defaultKernel = NULL;   defaultKernel = NULL;
4485      }      }
4486        else if (defaultKernel && (defaultIndex >= 0)) {
4487     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4488      "may not be used together\n"));
4489     return 1;
4490        }
4491    
4492      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4493   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4494   "is used\n"));   "is used\n"));
4495   return 1;   return 1;
4496      }      }
4497    
4498      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4499   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4500          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4501     && (defaultIndex == -1)) {
4502   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4503   return 1;   return 1;
4504      }      }
# Line 3010  int main(int argc, const char ** argv) { Line 4525  int main(int argc, const char ** argv) {
4525      }      }
4526    
4527      if (bootloaderProbe) {      if (bootloaderProbe) {
4528   int lrc = 0, grc = 0, erc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4529   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4530    
4531     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4532     if (grub2config) {
4533        gconfig = readConfig(grub2config, &grub2ConfigType);
4534        if (!gconfig)
4535     gr2c = 1;
4536        else
4537     gr2c = checkForGrub2(gconfig);
4538     }
4539    
4540   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4541      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4542        gconfig = readConfig(grubconfig, &grubConfigType);
4543      if (!gconfig)      if (!gconfig)
4544   grc = 1;   grc = 1;
4545      else      else
# Line 3029  int main(int argc, const char ** argv) { Line 4554  int main(int argc, const char ** argv) {
4554   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4555   }   }
4556    
4557     if (!access(eliloConfigType.defaultConfig, F_OK)) {
4558        econfig = readConfig(eliloConfigType.defaultConfig,
4559     &eliloConfigType);
4560        if (!econfig)
4561     erc = 1;
4562        else
4563     erc = checkForElilo(econfig);
4564     }
4565    
4566   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4567      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4568      if (!lconfig)      if (!lconfig)
4569   erc = 1;   extrc = 1;
4570      else      else
4571   erc = checkForExtLinux(lconfig);   extrc = checkForExtLinux(lconfig);
4572   }   }
4573    
4574   if (lrc == 1 || grc == 1) return 1;  
4575     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4576        yconfig = readConfig(yabootConfigType.defaultConfig,
4577     &yabootConfigType);
4578        if (!yconfig)
4579     yrc = 1;
4580        else
4581     yrc = checkForYaboot(yconfig);
4582     }
4583    
4584     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4585     erc == 1)
4586        return 1;
4587    
4588   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4589     if (gr2c == 2) printf("grub2\n");
4590   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4591   if (erc == 2) printf("extlinux\n");   if (extrc == 2) printf("extlinux\n");
4592     if (yrc == 2) printf("yaboot\n");
4593     if (erc == 2) printf("elilo\n");
4594    
4595   return 0;   return 0;
4596      }      }
4597    
4598        if (grubConfig == NULL) {
4599     printf("Could not find bootloader configuration file.\n");
4600     exit(1);
4601        }
4602    
4603      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4604      if (!config) return 1;      if (!config) return 1;
4605    
# Line 3055  int main(int argc, const char ** argv) { Line 4609  int main(int argc, const char ** argv) {
4609          char * rootspec;          char * rootspec;
4610    
4611   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4612     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4613     cfi->defaultIsSaved)
4614        config->defaultImage = 0;
4615   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4616   if (!entry) return 0;   if (!entry) return 0;
4617   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4618    
4619   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
4620   if (!line) return 0;   if (!line) return 0;
4621    
4622          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 3067  int main(int argc, const char ** argv) { Line 4624  int main(int argc, const char ** argv) {
4624                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4625    
4626   return 0;   return 0;
4627    
4628        } else if (displayDefaultTitle) {
4629     struct singleLine * line;
4630     struct singleEntry * entry;
4631    
4632     if (config->defaultImage == -1) return 0;
4633     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4634     cfi->defaultIsSaved)
4635        config->defaultImage = 0;
4636     entry = findEntryByIndex(config, config->defaultImage);
4637     if (!entry) return 0;
4638    
4639     if (!configureGrub2) {
4640      line = getLineByType(LT_TITLE, entry->lines);
4641      if (!line) return 0;
4642      printf("%s\n", line->elements[1].item);
4643    
4644     } else {
4645      char * title;
4646    
4647      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4648      line = getLineByType(LT_MENUENTRY, entry->lines);
4649      if (!line) return 0;
4650      title = grub2ExtractTitle(line);
4651      if (title)
4652        printf("%s\n", title);
4653     }
4654     return 0;
4655    
4656        } else if (displayDefaultIndex) {
4657            if (config->defaultImage == -1) return 0;
4658     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4659     cfi->defaultIsSaved)
4660        config->defaultImage = 0;
4661            printf("%i\n", config->defaultImage);
4662            return 0;
4663    
4664      } else if (kernelInfo)      } else if (kernelInfo)
4665   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4666    
# Line 3078  int main(int argc, const char ** argv) { Line 4672  int main(int argc, const char ** argv) {
4672      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4673      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4674      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4675      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4676      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4677      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4678                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4679        if (updateKernelPath && newKernelInitrd) {
4680        if (newMBKernel) {
4681        if (addMBInitrd(config, newMBKernel, updateKernelPath,
4682     bootPrefix, newKernelInitrd,
4683     newKernelTitle))
4684        return 1;
4685        } else {
4686        if (updateInitrd(config, updateKernelPath, bootPrefix,
4687     newKernelInitrd, newKernelTitle))
4688     return 1;
4689        }
4690        }
4691      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4692                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4693                       extraInitrds, extraInitrdCount,                       (const char **)extraInitrds, extraInitrdCount,
4694                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4695            
4696    
4697      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {
# Line 3095  int main(int argc, const char ** argv) { Line 4701  int main(int argc, const char ** argv) {
4701      }      }
4702    
4703      if (!outputFile)      if (!outputFile)
4704   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4705    
4706      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4707  }  }

Legend:
Removed from v.920  
changed lines
  Added in v.2972