Magellan Linux

Diff of /trunk/grubby/grubby.c

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

revision 1693 by niro, Fri Feb 17 23:21:08 2012 UTC revision 2980 by niro, Thu Jun 30 10:26:25 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        int defaultIsSaved;
164        int defaultIsUnquoted;
165      enum lineType_e entryStart;      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      .defaultConfig = "/boot/grub/grub.conf",      .findConfig = grubFindConfig,
217      .keywords = grubKeywords,      .keywords = grubKeywords,
218      .defaultIsIndex = 1,      .defaultIsIndex = 1,
219      .defaultSupportSaved = 1,      .defaultSupportSaved = 1,
# Line 148  struct configFileInfo grubConfigType = { Line 222  struct configFileInfo grubConfigType = {
222      .mbHyperFirst = 1,      .mbHyperFirst = 1,
223      .mbInitRdIsModule = 1,      .mbInitRdIsModule = 1,
224      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
225        .titlePosition = 1,
226    };
227    
228    struct keywordTypes grub2Keywords[] = {
229        { "menuentry",  LT_MENUENTRY,   ' ' },
230        { "}",          LT_ENTRY_END,   ' ' },
231        { "echo",       LT_ECHO,        ' ' },
232        { "set",        LT_SET_VARIABLE,' ', '=' },
233        { "root",       LT_BOOTROOT,    ' ' },
234        { "default",    LT_DEFAULT,     ' ' },
235        { "fallback",   LT_FALLBACK,    ' ' },
236        { "linux",      LT_KERNEL,      ' ' },
237        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
238        { "linux16",    LT_KERNEL_16,   ' ' },
239        { "initrd",     LT_INITRD,      ' ', ' ' },
240        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
241        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
242        { "module",     LT_MBMODULE,    ' ' },
243        { "kernel",     LT_HYPER,       ' ' },
244        { "devicetree", LT_DEVTREE,  ' ' },
245        { NULL, 0, 0 },
246    };
247    
248    const char *grub2FindConfig(struct configFileInfo *cfi) {
249        static const char *configFiles[] = {
250     "/boot/grub/grub-efi.cfg",
251     "/boot/grub/grub.cfg",
252     NULL
253        };
254        static int i = -1;
255        static const char *grub_cfg = "/boot/grub/grub.cfg";
256        int rc = -1;
257    
258        if (i == -1) {
259     for (i = 0; configFiles[i] != NULL; i++) {
260        dbgPrintf("Checking \"%s\": ", configFiles[i]);
261        if ((rc = access(configFiles[i], R_OK))) {
262     if (errno == EACCES) {
263        printf("Unable to access bootloader configuration file "
264           "\"%s\": %m\n", configFiles[i]);
265        exit(1);
266     }
267     continue;
268        } else {
269     dbgPrintf("found\n");
270     return configFiles[i];
271        }
272     }
273        }
274    
275        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
276         * that isn't in grub1, and if it exists, return the config file path
277         * that they use. */
278        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
279     dbgPrintf("found\n");
280     return grub_cfg;
281        }
282    
283        dbgPrintf("not found\n");
284        return configFiles[i];
285    }
286    
287    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
288    static char *grub2GetEnv(struct configFileInfo *info, char *name)
289    {
290        static char buf[1025];
291        char *s = NULL;
292        char *ret = NULL;
293        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
294        int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name);
295    
296        if (rc < 0)
297     return NULL;
298    
299        FILE *f = popen(s, "r");
300        if (!f)
301     goto out;
302    
303        memset(buf, '\0', sizeof (buf));
304        ret = fgets(buf, 1024, f);
305        pclose(f);
306    
307        if (ret) {
308     ret += strlen(name) + 1;
309     ret[strlen(ret) - 1] = '\0';
310        }
311        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
312    out:
313        free(s);
314        return ret;
315    }
316    
317    static int sPopCount(const char *s, const char *c)
318    {
319        int ret = 0;
320        if (!s)
321     return -1;
322        for (int i = 0; s[i] != '\0'; i++)
323     for (int j = 0; c[j] != '\0'; j++)
324        if (s[i] == c[j])
325     ret++;
326        return ret;
327    }
328    
329    static char *shellEscape(const char *s)
330    {
331        int l = strlen(s) + sPopCount(s, "'") * 2;
332    
333        char *ret = calloc(l+1, sizeof (*ret));
334        if (!ret)
335     return NULL;
336        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
337     if (s[i] == '\'')
338        ret[j++] = '\\';
339     ret[j] = s[i];
340        }
341        return ret;
342    }
343    
344    static void unquote(char *s)
345    {
346        int l = strlen(s);
347    
348        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
349     memmove(s, s+1, l-2);
350     s[l-2] = '\0';
351        }
352    }
353    
354    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
355    {
356        char *s = NULL;
357        int rc = 0;
358        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
359    
360        unquote(value);
361        value = shellEscape(value);
362        if (!value)
363        return -1;
364    
365        rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value);
366        free(value);
367        if (rc <0)
368     return -1;
369    
370        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
371        rc = system(s);
372        free(s);
373        return rc;
374    }
375    
376    /* this is a gigantic hack to avoid clobbering grub2 variables... */
377    static int is_special_grub2_variable(const char *name)
378    {
379        if (!strcmp(name,"\"${next_entry}\""))
380     return 1;
381        if (!strcmp(name,"\"${prev_saved_entry}\""))
382     return 1;
383        return 0;
384    }
385    
386    int sizeOfSingleLine(struct singleLine * line) {
387      int count = 0;
388    
389      for (int i = 0; i < line->numElements; i++) {
390        int indentSize = 0;
391    
392        count = count + strlen(line->elements[i].item);
393    
394        indentSize = strlen(line->elements[i].indent);
395        if (indentSize > 0)
396          count = count + indentSize;
397        else
398          /* be extra safe and add room for whitespaces */
399          count = count + 1;
400      }
401    
402      /* room for trailing terminator */
403      count = count + 1;
404    
405      return count;
406    }
407    
408    static int isquote(char q)
409    {
410        if (q == '\'' || q == '\"')
411     return 1;
412        return 0;
413    }
414    
415    static int iskernel(enum lineType_e type) {
416        return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
417    }
418    
419    static int isinitrd(enum lineType_e type) {
420        return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
421    }
422    
423    char *grub2ExtractTitle(struct singleLine * line) {
424        char * current;
425        char * current_indent;
426        int current_len;
427        int current_indent_len;
428        int i;
429    
430        /* bail out if line does not start with menuentry */
431        if (strcmp(line->elements[0].item, "menuentry"))
432          return NULL;
433    
434        i = 1;
435        current = line->elements[i].item;
436        current_len = strlen(current);
437    
438        /* if second word is quoted, strip the quotes and return single word */
439        if (isquote(*current) && isquote(current[current_len - 1])) {
440     char *tmp;
441    
442     tmp = strdup(current);
443     *(tmp + current_len - 1) = '\0';
444     return ++tmp;
445        }
446    
447        /* if no quotes, return second word verbatim */
448        if (!isquote(*current))
449     return current;
450    
451        /* second element start with a quote, so we have to find the element
452         * whose last character is also quote (assuming it's the closing one) */
453        int resultMaxSize;
454        char * result;
455        
456        resultMaxSize = sizeOfSingleLine(line);
457        result = malloc(resultMaxSize);
458        snprintf(result, resultMaxSize, "%s", ++current);
459        
460        i++;
461        for (; i < line->numElements; ++i) {
462     current = line->elements[i].item;
463     current_len = strlen(current);
464     current_indent = line->elements[i].indent;
465     current_indent_len = strlen(current_indent);
466    
467     strncat(result, current_indent, current_indent_len);
468     if (!isquote(current[current_len-1])) {
469        strncat(result, current, current_len);
470     } else {
471        strncat(result, current, current_len - 1);
472        break;
473     }
474        }
475        return result;
476    }
477    
478    struct configFileInfo grub2ConfigType = {
479        .findConfig = grub2FindConfig,
480        .getEnv = grub2GetEnv,
481        .setEnv = grub2SetEnv,
482        .keywords = grub2Keywords,
483        .defaultIsIndex = 1,
484        .defaultSupportSaved = 1,
485        .defaultIsVariable = 1,
486        .entryStart = LT_MENUENTRY,
487        .entryEnd = LT_ENTRY_END,
488        .titlePosition = 1,
489        .needsBootPrefix = 1,
490        .mbHyperFirst = 1,
491        .mbInitRdIsModule = 1,
492        .mbAllowExtraInitRds = 1,
493  };  };
494    
495  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 241  struct keywordTypes extlinuxKeywords[] = Line 583  struct keywordTypes extlinuxKeywords[] =
583      { "initrd",    LT_INITRD,      ' ', ',' },      { "initrd",    LT_INITRD,      ' ', ',' },
584      { "append",    LT_KERNELARGS,  ' ' },      { "append",    LT_KERNELARGS,  ' ' },
585      { "prompt",     LT_UNKNOWN,     ' ' },      { "prompt",     LT_UNKNOWN,     ' ' },
586        { "fdt",        LT_DEVTREE,     ' ' },
587        { "fdtdir",     LT_DEVTREE,     ' ' },
588      { NULL,    0, 0 },      { NULL,    0, 0 },
589  };  };
590  int useextlinuxmenu;  int useextlinuxmenu;
# Line 251  struct configFileInfo eliloConfigType = Line 595  struct configFileInfo eliloConfigType =
595      .needsBootPrefix = 1,      .needsBootPrefix = 1,
596      .argsInQuotes = 1,      .argsInQuotes = 1,
597      .mbConcatArgs = 1,      .mbConcatArgs = 1,
598        .titlePosition = 1,
599  };  };
600    
601  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
# Line 259  struct configFileInfo liloConfigType = { Line 604  struct configFileInfo liloConfigType = {
604      .entryStart = LT_KERNEL,      .entryStart = LT_KERNEL,
605      .argsInQuotes = 1,      .argsInQuotes = 1,
606      .maxTitleLength = 15,      .maxTitleLength = 15,
607        .titlePosition = 1,
608  };  };
609    
610  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
# Line 269  struct configFileInfo yabootConfigType = Line 615  struct configFileInfo yabootConfigType =
615      .argsInQuotes = 1,      .argsInQuotes = 1,
616      .maxTitleLength = 15,      .maxTitleLength = 15,
617      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
618        .titlePosition = 1,
619  };  };
620    
621  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
# Line 278  struct configFileInfo siloConfigType = { Line 625  struct configFileInfo siloConfigType = {
625      .needsBootPrefix = 1,      .needsBootPrefix = 1,
626      .argsInQuotes = 1,      .argsInQuotes = 1,
627      .maxTitleLength = 15,      .maxTitleLength = 15,
628        .titlePosition = 1,
629  };  };
630    
631  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
# Line 291  struct configFileInfo ziplConfigType = { Line 639  struct configFileInfo ziplConfigType = {
639  struct configFileInfo extlinuxConfigType = {  struct configFileInfo extlinuxConfigType = {
640      .defaultConfig = "/boot/extlinux/extlinux.conf",      .defaultConfig = "/boot/extlinux/extlinux.conf",
641      .keywords = extlinuxKeywords,      .keywords = extlinuxKeywords,
642        .caseInsensitive = 1,
643      .entryStart = LT_TITLE,      .entryStart = LT_TITLE,
644      .needsBootPrefix = 1,      .needsBootPrefix = 1,
645      .maxTitleLength = 255,      .maxTitleLength = 255,
646      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
647        .defaultIsUnquoted = 1,
648        .titlePosition = 1,
649  };  };
650    
651  struct grubConfig {  struct grubConfig {
# Line 315  struct singleEntry * findEntryByIndex(st Line 666  struct singleEntry * findEntryByIndex(st
666  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
667       const char * path, const char * prefix,       const char * path, const char * prefix,
668       int * index);       int * index);
669    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
670          int * index);
671  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
672  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
673  struct singleLine * lineDup(struct singleLine * line);  struct singleLine * lineDup(struct singleLine * line);
# Line 324  static int lineWrite(FILE * out, struct Line 677  static int lineWrite(FILE * out, struct
677  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
678         struct configFileInfo * cfi);         struct configFileInfo * cfi);
679  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
680    static void requote(struct singleLine *line, struct configFileInfo * cfi);
681  static void insertElement(struct singleLine * line,  static void insertElement(struct singleLine * line,
682    const char * item, int insertHere,    const char * item, int insertHere,
683    struct configFileInfo * cfi);    struct configFileInfo * cfi);
# Line 378  static char * sdupprintf(const char *for Line 732  static char * sdupprintf(const char *for
732      return buf;      return buf;
733  }  }
734    
735    static enum lineType_e preferredLineType(enum lineType_e type,
736     struct configFileInfo *cfi) {
737        if (isEfi && cfi == &grub2ConfigType) {
738     switch (type) {
739     case LT_KERNEL:
740        return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
741     case LT_INITRD:
742        return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
743     default:
744        return type;
745     }
746    #if defined(__i386__) || defined(__x86_64__)
747        } else if (cfi == &grub2ConfigType) {
748     switch (type) {
749     case LT_KERNEL:
750        return LT_KERNEL_16;
751     case LT_INITRD:
752        return LT_INITRD_16;
753     default:
754        return type;
755     }
756    #endif
757        }
758        return type;
759    }
760    
761  static struct keywordTypes * getKeywordByType(enum lineType_e type,  static struct keywordTypes * getKeywordByType(enum lineType_e type,
762        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
763      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
     for (kw = cfi->keywords; kw->key; kw++) {  
764   if (kw->type == type)   if (kw->type == type)
765      return kw;      return kw;
766      }      }
767      return NULL;      return NULL;
768  }  }
769    
770    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
771        struct keywordTypes *kt = getKeywordByType(type, cfi);
772        if (kt)
773     return kt->key;
774        return "unknown";
775    }
776    
777  static char * getpathbyspec(char *device) {  static char * getpathbyspec(char *device) {
778      if (!blkid)      if (!blkid)
779          blkid_get_cache(&blkid, NULL);          blkid_get_cache(&blkid, NULL);
# Line 404  static char * getuuidbydev(char *device) Line 790  static char * getuuidbydev(char *device)
790    
791  static enum lineType_e getTypeByKeyword(char * keyword,  static enum lineType_e getTypeByKeyword(char * keyword,
792   struct configFileInfo * cfi) {   struct configFileInfo * cfi) {
793      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
794      for (kw = cfi->keywords; kw->key; kw++) {   if (cfi->caseInsensitive) {
795   if (!strcmp(keyword, kw->key))      if (!strcasecmp(keyword, kw->key))
796      return kw->type;                  return kw->type;
797     } else {
798        if (!strcmp(keyword, kw->key))
799            return kw->type;
800     }
801      }      }
802      return LT_UNKNOWN;      return LT_UNKNOWN;
803  }  }
# Line 444  static int isEntryStart(struct singleLin Line 834  static int isEntryStart(struct singleLin
834  }  }
835    
836  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
837  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct grubConfig *cfg, struct singleLine * line) {
838      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it */
839      char * title;      char * title = NULL;
840      title = strdup(line->elements[0].item);      if (cfg->cfi == &grub2ConfigType)
841      title++;   return grub2ExtractTitle(line);
842      *(title + strlen(title) - 1) = '\0';      if (line->type == LT_TITLE) {
843     char *tmp = line->elements[cfg->cfi->titlePosition].item;
844     if (cfg->cfi->titleBracketed) {
845        tmp++;
846        title = strdup(tmp);
847        *(title + strlen(title) - 1) = '\0';
848     } else {
849        title = strdup(tmp);
850     }
851        } else if (line->type == LT_MENUENTRY)
852     title = strdup(line->elements[1].item);
853        else
854     return NULL;
855      return title;      return title;
856  }  }
857    
# Line 492  static void lineInit(struct singleLine * Line 894  static void lineInit(struct singleLine *
894  }  }
895    
896  struct singleLine * lineDup(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
     int i;  
897      struct singleLine * newLine = malloc(sizeof(*newLine));      struct singleLine * newLine = malloc(sizeof(*newLine));
898    
899      newLine->indent = strdup(line->indent);      newLine->indent = strdup(line->indent);
# Line 502  struct singleLine * lineDup(struct singl Line 903  struct singleLine * lineDup(struct singl
903      newLine->elements = malloc(sizeof(*newLine->elements) *      newLine->elements = malloc(sizeof(*newLine->elements) *
904         newLine->numElements);         newLine->numElements);
905    
906      for (i = 0; i < newLine->numElements; i++) {      for (int i = 0; i < newLine->numElements; i++) {
907   newLine->elements[i].indent = strdup(line->elements[i].indent);   newLine->elements[i].indent = strdup(line->elements[i].indent);
908   newLine->elements[i].item = strdup(line->elements[i].item);   newLine->elements[i].item = strdup(line->elements[i].item);
909      }      }
# Line 511  struct singleLine * lineDup(struct singl Line 912  struct singleLine * lineDup(struct singl
912  }  }
913    
914  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
     int i;  
   
915      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
916    
917      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
918   free(line->elements[i].item);   free(line->elements[i].item);
919   free(line->elements[i].indent);   free(line->elements[i].indent);
920      }      }
# Line 526  static void lineFree(struct singleLine * Line 925  static void lineFree(struct singleLine *
925    
926  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
927       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
928      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
929    
930      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
931     /* Need to handle this, because we strip the quotes from
932     * menuentry when read it. */
933     if (line->type == LT_MENUENTRY && i == 1) {
934        if(!isquote(*line->elements[i].item))
935     fprintf(out, "\'%s\'", line->elements[i].item);
936        else
937     fprintf(out, "%s", line->elements[i].item);
938        fprintf(out, "%s", line->elements[i].indent);
939    
940        continue;
941     }
942    
943   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
944      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
945    
# Line 624  static int getNextLine(char ** bufPtr, s Line 1033  static int getNextLine(char ** bufPtr, s
1033      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
1034   char * fullLine;   char * fullLine;
1035   int len;   int len;
  int i;  
1036    
1037   len = strlen(line->indent);   len = strlen(line->indent);
1038   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
1039      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
1040     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1041    
# Line 636  static int getNextLine(char ** bufPtr, s Line 1044  static int getNextLine(char ** bufPtr, s
1044   free(line->indent);   free(line->indent);
1045   line->indent = fullLine;   line->indent = fullLine;
1046    
1047   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1048      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1049      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1050      free(line->elements[i].item);      free(line->elements[i].item);
# Line 655  static int getNextLine(char ** bufPtr, s Line 1063  static int getNextLine(char ** bufPtr, s
1063   * elements up more   * elements up more
1064   */   */
1065   if (!isspace(kw->separatorChar)) {   if (!isspace(kw->separatorChar)) {
     int i;  
1066      char indent[2] = "";      char indent[2] = "";
1067      indent[0] = kw->separatorChar;      indent[0] = kw->separatorChar;
1068      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1069   char *p;   char *p;
  int j;  
1070   int numNewElements;   int numNewElements;
1071    
1072   numNewElements = 0;   numNewElements = 0;
# Line 676  static int getNextLine(char ** bufPtr, s Line 1082  static int getNextLine(char ** bufPtr, s
1082      sizeof(*line->elements) * elementsAlloced);      sizeof(*line->elements) * elementsAlloced);
1083   }   }
1084    
1085   for (j = line->numElements; j > i; j--) {   for (int j = line->numElements; j > i; j--) {
1086   line->elements[j + numNewElements] = line->elements[j];   line->elements[j + numNewElements] = line->elements[j];
1087   }   }
1088   line->numElements += numNewElements;   line->numElements += numNewElements;
# Line 689  static int getNextLine(char ** bufPtr, s Line 1095  static int getNextLine(char ** bufPtr, s
1095   break;   break;
1096   }   }
1097    
1098   free(line->elements[i].indent);   line->elements[i + 1].indent = line->elements[i].indent;
1099   line->elements[i].indent = strdup(indent);   line->elements[i].indent = strdup(indent);
1100   *p++ = '\0';   *p++ = '\0';
1101   i++;   i++;
1102   line->elements[i].item = strdup(p);   line->elements[i].item = strdup(p);
  line->elements[i].indent = strdup("");  
  p = line->elements[i].item;  
1103   }   }
1104      }      }
1105   }   }
# Line 705  static int getNextLine(char ** bufPtr, s Line 1109  static int getNextLine(char ** bufPtr, s
1109      return 0;      return 0;
1110  }  }
1111    
1112    static int isnumber(const char *s)
1113    {
1114        int i;
1115        for (i = 0; s[i] != '\0'; i++)
1116     if (s[i] < '0' || s[i] > '9')
1117        return 0;
1118        return i;
1119    }
1120    
1121  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1122        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1123      int in;      int in;
# Line 716  static struct grubConfig * readConfig(co Line 1129  static struct grubConfig * readConfig(co
1129      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1130      char * end;      char * end;
1131      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1132      int i, len;      int len;
1133      char * buf;      char * buf;
1134    
1135      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1136            printf("Could not find bootloader configuration\n");
1137            exit(1);
1138        } else if (!strcmp(inName, "-")) {
1139   in = 0;   in = 0;
1140      } else {      } else {
1141   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 762  static struct grubConfig * readConfig(co Line 1178  static struct grubConfig * readConfig(co
1178      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1179   }   }
1180    
1181   if (isEntryStart(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1182      sawEntry = 1;      sawEntry = 1;
1183      if (!entry) {      if (!entry) {
1184   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 778  static struct grubConfig * readConfig(co Line 1194  static struct grubConfig * readConfig(co
1194      entry->next = NULL;      entry->next = NULL;
1195   }   }
1196    
1197   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1198      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1199      defaultLine = line;      dbgPrintf("%s", line->indent);
1200        for (int i = 0; i < line->numElements; i++)
1201     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1202        dbgPrintf("\n");
1203        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1204        if (kwType && line->numElements == 3 &&
1205        !strcmp(line->elements[1].item, kwType->key) &&
1206        !is_special_grub2_variable(line->elements[2].item)) {
1207     dbgPrintf("Line sets default config\n");
1208     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1209     defaultLine = line;
1210        }
1211    
1212          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1213      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1214       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1215       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1216       */       */
1217      if (entry->multiboot)      if (entry && entry->multiboot)
1218   line->type = LT_HYPER;   line->type = LT_HYPER;
1219    
1220          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 796  static struct grubConfig * readConfig(co Line 1223  static struct grubConfig * readConfig(co
1223       * This only applies to grub, but that's the only place we       * This only applies to grub, but that's the only place we
1224       * should find LT_MBMODULE lines anyway.       * should find LT_MBMODULE lines anyway.
1225       */       */
1226      struct singleLine * l;      for (struct singleLine *l = entry->lines; l; l = l->next) {
     for (l = entry->lines; l; l = l->next) {  
1227   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1228      break;      break;
1229   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1230      l->type = LT_HYPER;      l->type = LT_HYPER;
1231      break;      break;
1232   }   }
# Line 814  static struct grubConfig * readConfig(co Line 1240  static struct grubConfig * readConfig(co
1240      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1241      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1242    
1243   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1244      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1245        /* make the title/default a single argument (undoing our parsing) */
1246      len = 0;      len = 0;
1247      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1248   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1249   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1250      }      }
1251      buf = malloc(len + 1);      buf = malloc(len + 1);
1252      *buf = '\0';      *buf = '\0';
1253    
1254      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1255   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1256   free(line->elements[i].item);   free(line->elements[i].item);
1257    
# Line 838  static struct grubConfig * readConfig(co Line 1265  static struct grubConfig * readConfig(co
1265      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1266      line->elements[1].item = buf;      line->elements[1].item = buf;
1267      line->numElements = 2;      line->numElements = 2;
1268     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1269        /* let --remove-kernel="TITLE=what" work */
1270        len = 0;
1271        char *extras;
1272        char *title;
1273    
1274        for (int i = 1; i < line->numElements; i++) {
1275     len += strlen(line->elements[i].item);
1276     len += strlen(line->elements[i].indent);
1277        }
1278        buf = malloc(len + 1);
1279        *buf = '\0';
1280    
1281        /* allocate mem for extra flags. */
1282        extras = malloc(len + 1);
1283        *extras = '\0';
1284    
1285        /* get title. */
1286        for (int i = 0; i < line->numElements; i++) {
1287     if (!strcmp(line->elements[i].item, "menuentry"))
1288        continue;
1289     if (isquote(*line->elements[i].item))
1290        title = line->elements[i].item + 1;
1291     else
1292        title = line->elements[i].item;
1293    
1294     len = strlen(title);
1295            if (isquote(title[len-1])) {
1296        strncat(buf, title,len-1);
1297        break;
1298     } else {
1299        strcat(buf, title);
1300        strcat(buf, line->elements[i].indent);
1301     }
1302        }
1303    
1304        /* get extras */
1305        int count = 0;
1306        for (int i = 0; i < line->numElements; i++) {
1307     if (count >= 2) {
1308        strcat(extras, line->elements[i].item);
1309        strcat(extras, line->elements[i].indent);
1310     }
1311    
1312     if (!strcmp(line->elements[i].item, "menuentry"))
1313        continue;
1314    
1315     /* count ' or ", there should be two in menuentry line. */
1316     if (isquote(*line->elements[i].item))
1317        count++;
1318    
1319     len = strlen(line->elements[i].item);
1320    
1321     if (isquote(line->elements[i].item[len -1]))
1322        count++;
1323    
1324     /* ok, we get the final ' or ", others are extras. */
1325                }
1326        line->elements[1].indent =
1327     line->elements[line->numElements - 2].indent;
1328        line->elements[1].item = buf;
1329        line->elements[2].indent =
1330     line->elements[line->numElements - 2].indent;
1331        line->elements[2].item = extras;
1332        line->numElements = 3;
1333   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1334      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1335         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 847  static struct grubConfig * readConfig(co Line 1338  static struct grubConfig * readConfig(co
1338      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1339   int last, len;   int last, len;
1340    
1341   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1342      memmove(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1343      strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1344    
1345   last = line->numElements - 1;   last = line->numElements - 1;
1346   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1347   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1348      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1349      }      }
1350   }   }
1351    
1352     if (line->type == LT_DEFAULT && line->numElements == 2) {
1353        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1354        defaultLine = line;
1355     }
1356    
1357   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1358     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1359     probably responsible for putting new images in the wrong     probably responsible for putting new images in the wrong
# Line 891  static struct grubConfig * readConfig(co Line 1387  static struct grubConfig * readConfig(co
1387   entry->lines = line;   entry->lines = line;
1388      else      else
1389   last->next = line;   last->next = line;
1390      dbgPrintf("readConfig added %d to %p\n", line->type, entry);      dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1391    
1392        /* we could have seen this outside of an entry... if so, we
1393         * ignore it like any other line we don't grok */
1394        if (line->type == LT_ENTRY_END && sawEntry)
1395     sawEntry = 0;
1396   } else {   } else {
1397      if (!cfg->theLines)      if (!cfg->theLines)
1398   cfg->theLines = line;   cfg->theLines = line;
1399      else      else
1400   last->next = line;   last->next = line;
1401      dbgPrintf("readConfig added %d to cfg\n", line->type);      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1402   }   }
1403    
1404   last = line;   last = line;
# Line 905  static struct grubConfig * readConfig(co Line 1406  static struct grubConfig * readConfig(co
1406    
1407      free(incoming);      free(incoming);
1408    
1409        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1410      if (defaultLine) {      if (defaultLine) {
1411   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1412        cfi->defaultSupportSaved &&
1413        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1414     cfg->cfi->defaultIsSaved = 1;
1415     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1416     if (cfg->cfi->getEnv) {
1417        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1418        if (defTitle) {
1419     int index = 0;
1420     if (isnumber(defTitle)) {
1421        index = atoi(defTitle);
1422        entry = findEntryByIndex(cfg, index);
1423     } else {
1424        entry = findEntryByTitle(cfg, defTitle, &index);
1425     }
1426     if (entry)
1427        cfg->defaultImage = index;
1428        }
1429     }
1430     } else if (cfi->defaultIsVariable) {
1431        char *value = defaultLine->elements[2].item;
1432        while (*value && (*value == '"' || *value == '\'' ||
1433        *value == ' ' || *value == '\t'))
1434     value++;
1435        cfg->defaultImage = strtol(value, &end, 10);
1436        while (*end && (*end == '"' || *end == '\'' ||
1437        *end == ' ' || *end == '\t'))
1438     end++;
1439        if (*end) cfg->defaultImage = -1;
1440     } else if (cfi->defaultSupportSaved &&
1441   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1442      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1443   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1444      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1445      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1446   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1447      i = 0;      int i = 0;
1448      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1449   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1450      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 924  static struct grubConfig * readConfig(co Line 1455  static struct grubConfig * readConfig(co
1455                                  line->elements[1].item)) break;                                  line->elements[1].item)) break;
1456                  } else if (line) {                  } else if (line) {
1457                      if (!strcmp(defaultLine->elements[1].item,                      if (!strcmp(defaultLine->elements[1].item,
1458                                  extractTitle(line))) break;                                  extractTitle(cfg, line))) break;
1459                  }                  }
1460   i++;   i++;
1461   entry = NULL;   entry = NULL;
# Line 936  static struct grubConfig * readConfig(co Line 1467  static struct grubConfig * readConfig(co
1467          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1468      }      }
1469   }   }
1470        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1471     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1472     if (defTitle) {
1473        int index = 0;
1474        if (isnumber(defTitle)) {
1475     index = atoi(defTitle);
1476     entry = findEntryByIndex(cfg, index);
1477        } else {
1478     entry = findEntryByTitle(cfg, defTitle, &index);
1479        }
1480        if (entry)
1481     cfg->defaultImage = index;
1482     }
1483      } else {      } else {
1484          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1485      }      }
# Line 953  static void writeDefault(FILE * out, cha Line 1497  static void writeDefault(FILE * out, cha
1497    
1498      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1499   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1500      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1501     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1502     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1503        char *title;
1504        entry = findEntryByIndex(cfg, cfg->defaultImage);
1505        line = getLineByType(LT_MENUENTRY, entry->lines);
1506        if (!line)
1507     line = getLineByType(LT_TITLE, entry->lines);
1508        if (line) {
1509     title = extractTitle(cfg, line);
1510     if (title)
1511        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1512        }
1513     }
1514        } else if (cfg->defaultImage > -1) {
1515   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1516      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1517      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1518     cfg->defaultImage);
1519        } else {
1520     fprintf(out, "%sdefault%s%d\n", indent, separator,
1521     cfg->defaultImage);
1522        }
1523   } else {   } else {
1524      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1525    
# Line 981  static void writeDefault(FILE * out, cha Line 1544  static void writeDefault(FILE * out, cha
1544              else if (line && (line->numElements == 1) &&              else if (line && (line->numElements == 1) &&
1545                       cfg->cfi->titleBracketed) {                       cfg->cfi->titleBracketed) {
1546   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
1547                          extractTitle(line));                          extractTitle(cfg, line));
1548              }              }
1549   }   }
1550      }      }
# Line 1008  static int writeConfig(struct grubConfig Line 1571  static int writeConfig(struct grubConfig
1571    
1572      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1573         directory to the dir of the symlink */         directory to the dir of the symlink */
1574              rc = chdir(dirname(strdupa(outName)));      char *dir = strdupa(outName);
1575        rc = chdir(dirname(dir));
1576      do {      do {
1577   buf = alloca(len + 1);   buf = alloca(len + 1);
1578   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1046  static int writeConfig(struct grubConfig Line 1610  static int writeConfig(struct grubConfig
1610      }      }
1611    
1612      line = cfg->theLines;      line = cfg->theLines;
1613        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1614      while (line) {      while (line) {
1615   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1616     line->numElements == 3 &&
1617     !strcmp(line->elements[1].item, defaultKw->key) &&
1618     !is_special_grub2_variable(line->elements[2].item)) {
1619        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1620        needs &= ~MAIN_DEFAULT;
1621     } else if (line->type == LT_DEFAULT) {
1622      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1623      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1624   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 1140  static char *findDiskForRoot() Line 1711  static char *findDiskForRoot()
1711      buf[rc] = '\0';      buf[rc] = '\0';
1712      chptr = buf;      chptr = buf;
1713    
1714        char *foundanswer = NULL;
1715    
1716      while (chptr && chptr != buf+rc) {      while (chptr && chptr != buf+rc) {
1717          devname = chptr;          devname = chptr;
1718    
# Line 1167  static char *findDiskForRoot() Line 1740  static char *findDiskForRoot()
1740           * for '/' obviously.           * for '/' obviously.
1741           */           */
1742          if (*(++chptr) == '/' && *(++chptr) == ' ') {          if (*(++chptr) == '/' && *(++chptr) == ' ') {
1743              /*              /* remember the last / entry in mtab */
1744               * Move back 2, which is the first space after the device name, set             foundanswer = devname;
              * it to \0 so strdup will just get the devicename.  
              */  
             chptr -= 2;  
             *chptr = '\0';  
             return strdup(devname);  
1745          }          }
1746    
1747          /* Next line */          /* Next line */
# Line 1182  static char *findDiskForRoot() Line 1750  static char *findDiskForRoot()
1750              chptr++;              chptr++;
1751      }      }
1752    
1753        /* Return the last / entry found */
1754        if (foundanswer) {
1755            chptr = strchr(foundanswer, ' ');
1756            *chptr = '\0';
1757            return strdup(foundanswer);
1758        }
1759    
1760      return NULL;      return NULL;
1761  }  }
1762    
1763    void printEntry(struct singleEntry * entry, FILE *f) {
1764        int i;
1765        struct singleLine * line;
1766    
1767        for (line = entry->lines; line; line = line->next) {
1768     log_message(f, "DBG: %s", line->indent);
1769     for (i = 0; i < line->numElements; i++) {
1770        /* Need to handle this, because we strip the quotes from
1771         * menuentry when read it. */
1772        if (line->type == LT_MENUENTRY && i == 1) {
1773     if(!isquote(*line->elements[i].item))
1774        log_message(f, "\'%s\'", line->elements[i].item);
1775     else
1776        log_message(f, "%s", line->elements[i].item);
1777     log_message(f, "%s", line->elements[i].indent);
1778    
1779     continue;
1780        }
1781        
1782        log_message(f, "%s%s",
1783        line->elements[i].item, line->elements[i].indent);
1784     }
1785     log_message(f, "\n");
1786        }
1787    }
1788    
1789    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1790    {
1791        static int once;
1792        va_list argp, argq;
1793    
1794        va_start(argp, fmt);
1795    
1796        va_copy(argq, argp);
1797        if (!once) {
1798     log_time(NULL);
1799     log_message(NULL, "command line: %s\n", saved_command_line);
1800        }
1801        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1802        log_vmessage(NULL, fmt, argq);
1803    
1804        printEntry(entry, NULL);
1805        va_end(argq);
1806    
1807        if (!debug) {
1808     once = 1;
1809         va_end(argp);
1810     return;
1811        }
1812    
1813        if (okay) {
1814     va_end(argp);
1815     return;
1816        }
1817    
1818        if (!once)
1819     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1820        once = 1;
1821        fprintf(stderr, "DBG: Image entry failed: ");
1822        vfprintf(stderr, fmt, argp);
1823        printEntry(entry, stderr);
1824        va_end(argp);
1825    }
1826    
1827    #define beginswith(s, c) ((s) && (s)[0] == (c))
1828    
1829    static int endswith(const char *s, char c)
1830    {
1831     int slen;
1832    
1833     if (!s || !s[0])
1834     return 0;
1835     slen = strlen(s) - 1;
1836    
1837     return s[slen] == c;
1838    }
1839    
1840  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1841    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1842      struct singleLine * line;      struct singleLine * line;
# Line 1194  int suitableImage(struct singleEntry * e Line 1846  int suitableImage(struct singleEntry * e
1846      char * rootspec;      char * rootspec;
1847      char * rootdev;      char * rootdev;
1848    
1849      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) {
1850     notSuitablePrintf(entry, 0, "marked to skip\n");
1851     return 0;
1852        }
1853    
1854      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1855      if (!line || line->numElements < 2) return 0;      if (!line) {
1856     notSuitablePrintf(entry, 0, "no line found\n");
1857     return 0;
1858        }
1859        if (line->numElements < 2) {
1860     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1861        line->numElements);
1862     return 0;
1863        }
1864    
1865      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1866        notSuitablePrintf(entry, 1, "\n");
1867        return 1;
1868        }
1869    
1870      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1871        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1872      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1873      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1874              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));      int hasslash = endswith(bootPrefix, '/') ||
1875      if (access(fullName, R_OK)) return 0;       beginswith(line->elements[1].item + rootspec_offset, '/');
1876        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1877                line->elements[1].item + rootspec_offset);
1878        if (access(fullName, R_OK)) {
1879     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1880     return 0;
1881        }
1882      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1883   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1884      if (i < line->numElements) {      if (i < line->numElements) {
# Line 1225  int suitableImage(struct singleEntry * e Line 1896  int suitableImage(struct singleEntry * e
1896      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1897    
1898              /* failed to find one */              /* failed to find one */
1899              if (!line) return 0;              if (!line) {
1900     notSuitablePrintf(entry, 0, "no line found\n");
1901     return 0;
1902                }
1903    
1904      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1905          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1906      if (i < line->numElements)      if (i < line->numElements)
1907          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1908      else {      else {
1909     notSuitablePrintf(entry, 0, "no root= entry found\n");
1910   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1911          return 0;          return 0;
1912              }              }
# Line 1239  int suitableImage(struct singleEntry * e Line 1914  int suitableImage(struct singleEntry * e
1914      }      }
1915    
1916      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1917      if (!dev)      if (!getpathbyspec(dev)) {
1918            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1919          return 0;          return 0;
1920        } else
1921     dev = getpathbyspec(dev);
1922    
1923      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1924      if (!rootdev)      if (!rootdev) {
1925            notSuitablePrintf(entry, 0, "can't find root device\n");
1926   return 0;   return 0;
1927        }
1928    
1929      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1930            notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1931     getuuidbydev(rootdev), getuuidbydev(dev));
1932          free(rootdev);          free(rootdev);
1933          return 0;          return 0;
1934      }      }
1935    
1936      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1937            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1938     getuuidbydev(rootdev), getuuidbydev(dev));
1939   free(rootdev);   free(rootdev);
1940          return 0;          return 0;
1941      }      }
1942    
1943      free(rootdev);      free(rootdev);
1944        notSuitablePrintf(entry, 1, "\n");
1945    
1946      return 1;      return 1;
1947  }  }
# Line 1290  struct singleEntry * findEntryByPath(str Line 1975  struct singleEntry * findEntryByPath(str
1975   }   }
1976    
1977   indexVars[i + 1] = -1;   indexVars[i + 1] = -1;
1978    
1979   i = 0;   i = 0;
1980   if (index) {   if (index) {
1981      while (i < *index) i++;      while (i < *index) {
1982      if (indexVars[i] == -1) return NULL;   i++;
1983     if (indexVars[i] == -1) return NULL;
1984        }
1985   }   }
1986    
1987   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1988   if (!entry) return NULL;   if (!entry) return NULL;
1989    
1990   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1991   if (!line) return NULL;   if (!line) return NULL;
1992    
1993   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1338  struct singleEntry * findEntryByPath(str Line 2025  struct singleEntry * findEntryByPath(str
2025    
2026   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
2027      prefix = "";      prefix = "";
2028      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
2029      kernel += 6;      kernel += 6;
2030   }   }
2031    
# Line 1349  struct singleEntry * findEntryByPath(str Line 2036  struct singleEntry * findEntryByPath(str
2036    
2037      /* check all the lines matching checkType */      /* check all the lines matching checkType */
2038      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2039   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
2040       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
2041       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2042   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
2043        ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2044     line = getLineByType(ct, line);
2045     if (!line)
2046        break;  /* not found in this entry */
2047    
2048   if (line && line->numElements >= 2) {   if (line && line->type != LT_MENUENTRY &&
2049     line->numElements >= 2) {
2050      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
2051      if (!strcmp(line->elements[1].item +      if (!strcmp(line->elements[1].item +
2052   ((rootspec != NULL) ? strlen(rootspec) : 0),   ((rootspec != NULL) ? strlen(rootspec) : 0),
2053   kernel + strlen(prefix)))   kernel + strlen(prefix)))
2054   break;   break;
2055   }   }
2056     if(line->type == LT_MENUENTRY &&
2057     !strcmp(line->elements[1].item, kernel))
2058        break;
2059      }      }
2060    
2061      /* make sure this entry has a kernel identifier; this skips      /* make sure this entry has a kernel identifier; this skips
2062       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2063       * unfortunate)       * unfortunate)
2064       */       */
2065      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2066   break; /* found 'im! */   break; /* found 'im! */
2067   }   }
2068    
# Line 1377  struct singleEntry * findEntryByPath(str Line 2072  struct singleEntry * findEntryByPath(str
2072      return entry;      return entry;
2073  }  }
2074    
2075    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2076          int * index) {
2077        struct singleEntry * entry;
2078        struct singleLine * line;
2079        int i;
2080        char * newtitle;
2081    
2082        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2083     if (index && i < *index)
2084        continue;
2085     line = getLineByType(LT_TITLE, entry->lines);
2086     if (!line)
2087        line = getLineByType(LT_MENUENTRY, entry->lines);
2088     if (!line)
2089        continue;
2090     newtitle = grub2ExtractTitle(line);
2091     if (!newtitle)
2092        continue;
2093     if (!strcmp(title, newtitle))
2094        break;
2095        }
2096    
2097        if (!entry)
2098     return NULL;
2099    
2100        if (index)
2101     *index = i;
2102        return entry;
2103    }
2104    
2105  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2106      struct singleEntry * entry;      struct singleEntry * entry;
2107    
# Line 1399  struct singleEntry * findTemplate(struct Line 2124  struct singleEntry * findTemplate(struct
2124      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2125      int index;      int index;
2126    
2127      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2128     if (cfg->cfi->getEnv) {
2129        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2130        if (defTitle) {
2131     int index = 0;
2132     if (isnumber(defTitle)) {
2133        index = atoi(defTitle);
2134        entry = findEntryByIndex(cfg, index);
2135     } else {
2136        entry = findEntryByTitle(cfg, defTitle, &index);
2137     }
2138     if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2139        cfg->defaultImage = index;
2140        if (indexPtr)
2141     *indexPtr = index;
2142        return entry;
2143     }
2144        }
2145     }
2146        } else if (cfg->defaultImage > -1) {
2147   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2148   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2149      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1452  void markRemovedImage(struct grubConfig Line 2196  void markRemovedImage(struct grubConfig
2196        const char * prefix) {        const char * prefix) {
2197      struct singleEntry * entry;      struct singleEntry * entry;
2198    
2199      if (!image) return;      if (!image)
2200     return;
2201    
2202        /* check and see if we're removing the default image */
2203        if (isdigit(*image)) {
2204     entry = findEntryByPath(cfg, image, prefix, NULL);
2205     if(entry)
2206        entry->skip = 1;
2207     return;
2208        }
2209    
2210      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2211   entry->skip = 1;   entry->skip = 1;
# Line 1460  void markRemovedImage(struct grubConfig Line 2213  void markRemovedImage(struct grubConfig
2213    
2214  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2215       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2216       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2217      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2218      int i, j;      int i, j;
2219    
2220      if (newIsDefault) {      if (newIsDefault) {
2221   config->defaultImage = 0;   config->defaultImage = 0;
2222   return;   return;
2223        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2224     if (findEntryByIndex(config, index))
2225        config->defaultImage = index;
2226     else
2227        config->defaultImage = -1;
2228     return;
2229      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2230   i = 0;   i = 0;
2231   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1479  void setDefaultImage(struct grubConfig * Line 2238  void setDefaultImage(struct grubConfig *
2238    
2239      /* 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
2240         changes */         changes */
2241      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2242     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2243        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2244        return;        return;
2245    
# Line 1533  void setFallbackImage(struct grubConfig Line 2293  void setFallbackImage(struct grubConfig
2293      }      }
2294  }  }
2295    
2296  void displayEntry(struct singleEntry * entry, const char * prefix, int index) {  void displayEntry(struct singleEntry * entry, const char * prefix, int index) {
2297      struct singleLine * line;      struct singleLine * line;
2298      char * root = NULL;      char * root = NULL;
2299      int i;      int i;
2300        int j;
2301    
2302        printf("index=%d\n", index);
2303    
2304        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2305        if (!line) {
2306            printf("non linux entry\n");
2307            return;
2308        }
2309    
2310        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2311     printf("kernel=%s\n", line->elements[1].item);
2312        else
2313     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2314    
2315        if (line->numElements >= 3) {
2316     printf("args=\"");
2317     i = 2;
2318     while (i < line->numElements) {
2319        if (!strncmp(line->elements[i].item, "root=", 5)) {
2320     root = line->elements[i].item + 5;
2321        } else {
2322     printf("%s%s", line->elements[i].item,
2323           line->elements[i].indent);
2324        }
2325    
2326        i++;
2327     }
2328     printf("\"\n");
2329        } else {
2330     line = getLineByType(LT_KERNELARGS, entry->lines);
2331     if (line) {
2332        char * s;
2333    
2334        printf("args=\"");
2335        i = 1;
2336        while (i < line->numElements) {
2337     if (!strncmp(line->elements[i].item, "root=", 5)) {
2338        root = line->elements[i].item + 5;
2339     } else {
2340        s = line->elements[i].item;
2341    
2342        printf("%s%s", s, line->elements[i].indent);
2343     }
2344    
2345     i++;
2346        }
2347    
2348        s = line->elements[i - 1].indent;
2349        printf("\"\n");
2350     }
2351        }
2352    
2353        if (!root) {
2354     line = getLineByType(LT_ROOT, entry->lines);
2355     if (line && line->numElements >= 2)
2356        root=line->elements[1].item;
2357        }
2358    
2359        if (root) {
2360     char * s = alloca(strlen(root) + 1);
2361    
2362     strcpy(s, root);
2363     if (s[strlen(s) - 1] == '"')
2364        s[strlen(s) - 1] = '\0';
2365     /* make sure the root doesn't have a trailing " */
2366     printf("root=%s\n", s);
2367        }
2368    
2369        line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2370    
2371        if (line && line->numElements >= 2) {
2372     if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2373        printf("initrd=");
2374     else
2375        printf("initrd=%s", prefix);
2376    
2377     for (i = 1; i < line->numElements; i++)
2378        printf("%s%s", line->elements[i].item, line->elements[i].indent);
2379     printf("\n");
2380        }
2381    
2382        line = getLineByType(LT_TITLE, entry->lines);
2383        if (line) {
2384     printf("title=%s\n", line->elements[1].item);
2385        } else {
2386     char * title;
2387     line = getLineByType(LT_MENUENTRY, entry->lines);
2388     if (line) {
2389        title = grub2ExtractTitle(line);
2390        if (title)
2391     printf("title=%s\n", title);
2392     }
2393        }
2394    
2395        for (j = 0, line = entry->lines; line; line = line->next) {
2396     if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
2397        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2398     printf("mbmodule%d=", j);
2399        else
2400     printf("mbmodule%d=%s", j, prefix);
2401    
2402        for (i = 1; i < line->numElements; i++)
2403     printf("%s%s", line->elements[i].item, line->elements[i].indent);
2404        printf("\n");
2405        j++;
2406     }
2407        }
2408    }
2409    
2410    int isSuseSystem(void) {
2411        const char * path;
2412        const static char default_path[] = "/etc/SuSE-release";
2413    
2414        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2415     path = default_path;
2416    
2417        if (!access(path, R_OK))
2418     return 1;
2419        return 0;
2420    }
2421    
2422    int isSuseGrubConf(const char * path) {
2423        FILE * grubConf;
2424        char * line = NULL;
2425        size_t len = 0, res = 0;
2426    
2427        grubConf = fopen(path, "r");
2428        if (!grubConf) {
2429            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2430     return 0;
2431        }
2432    
2433        while ((res = getline(&line, &len, grubConf)) != -1) {
2434     if (!strncmp(line, "setup", 5)) {
2435        fclose(grubConf);
2436        free(line);
2437        return 1;
2438     }
2439        }
2440    
2441        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2442          path);
2443    
2444        fclose(grubConf);
2445        free(line);
2446        return 0;
2447    }
2448    
2449    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2450        FILE * grubConf;
2451        char * line = NULL;
2452        size_t res = 0, len = 0;
2453    
2454        if (!path) return 1;
2455        if (!lbaPtr) return 1;
2456    
2457        grubConf = fopen(path, "r");
2458        if (!grubConf) return 1;
2459    
2460        while ((res = getline(&line, &len, grubConf)) != -1) {
2461     if (line[res - 1] == '\n')
2462        line[res - 1] = '\0';
2463     else if (len > res)
2464        line[res] = '\0';
2465     else {
2466        line = realloc(line, res + 1);
2467        line[res] = '\0';
2468     }
2469    
2470     if (!strncmp(line, "setup", 5)) {
2471        if (strstr(line, "--force-lba")) {
2472            *lbaPtr = 1;
2473        } else {
2474            *lbaPtr = 0;
2475        }
2476        dbgPrintf("lba: %i\n", *lbaPtr);
2477        break;
2478     }
2479        }
2480    
2481        free(line);
2482        fclose(grubConf);
2483        return 0;
2484    }
2485    
2486    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2487        FILE * grubConf;
2488        char * line = NULL;
2489        size_t res = 0, len = 0;
2490        char * lastParamPtr = NULL;
2491        char * secLastParamPtr = NULL;
2492        char installDeviceNumber = '\0';
2493        char * bounds = NULL;
2494    
2495        if (!path) return 1;
2496        if (!devicePtr) return 1;
2497    
2498        grubConf = fopen(path, "r");
2499        if (!grubConf) return 1;
2500    
2501        while ((res = getline(&line, &len, grubConf)) != -1) {
2502     if (strncmp(line, "setup", 5))
2503        continue;
2504    
2505     if (line[res - 1] == '\n')
2506        line[res - 1] = '\0';
2507     else if (len > res)
2508        line[res] = '\0';
2509     else {
2510        line = realloc(line, res + 1);
2511        line[res] = '\0';
2512     }
2513    
2514     lastParamPtr = bounds = line + res;
2515    
2516     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2517     while (!isspace(*lastParamPtr))
2518        lastParamPtr--;
2519     lastParamPtr++;
2520    
2521     secLastParamPtr = lastParamPtr - 2;
2522     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2523    
2524     if (lastParamPtr + 3 > bounds) {
2525        dbgPrintf("lastParamPtr going over boundary");
2526        fclose(grubConf);
2527        free(line);
2528        return 1;
2529     }
2530     if (!strncmp(lastParamPtr, "(hd", 3))
2531        lastParamPtr += 3;
2532     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2533    
2534     /*
2535     * Second last parameter will decide wether last parameter is
2536     * an IMAGE_DEVICE or INSTALL_DEVICE
2537     */
2538     while (!isspace(*secLastParamPtr))
2539        secLastParamPtr--;
2540     secLastParamPtr++;
2541    
2542     if (secLastParamPtr + 3 > bounds) {
2543        dbgPrintf("secLastParamPtr going over boundary");
2544        fclose(grubConf);
2545        free(line);
2546        return 1;
2547     }
2548     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2549     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2550        secLastParamPtr += 3;
2551        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2552        installDeviceNumber = *secLastParamPtr;
2553     } else {
2554        installDeviceNumber = *lastParamPtr;
2555     }
2556    
2557     *devicePtr = malloc(6);
2558     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2559     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2560     fclose(grubConf);
2561     free(line);
2562     return 0;
2563        }
2564    
2565        free(line);
2566        fclose(grubConf);
2567        return 1;
2568    }
2569    
2570    int grubGetBootFromDeviceMap(const char * device,
2571         char ** bootPtr) {
2572        FILE * deviceMap;
2573        char * line = NULL;
2574        size_t res = 0, len = 0;
2575        char * devicePtr;
2576        char * bounds = NULL;
2577        const char * path;
2578        const static char default_path[] = "/boot/grub/device.map";
2579    
2580        if (!device) return 1;
2581        if (!bootPtr) return 1;
2582    
2583        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2584     path = default_path;
2585    
2586        dbgPrintf("opening grub device.map file from: %s\n", path);
2587        deviceMap = fopen(path, "r");
2588        if (!deviceMap)
2589     return 1;
2590    
2591      printf("index=%d\n", index);      while ((res = getline(&line, &len, deviceMap)) != -1) {
2592            if (!strncmp(line, "#", 1))
2593        continue;
2594    
2595      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   if (line[res - 1] == '\n')
2596      if (!line) {      line[res - 1] = '\0';
2597          printf("non linux entry\n");   else if (len > res)
2598          return;      line[res] = '\0';
2599     else {
2600        line = realloc(line, res + 1);
2601        line[res] = '\0';
2602     }
2603    
2604     devicePtr = line;
2605     bounds = line + res;
2606    
2607     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2608        devicePtr++;
2609     dbgPrintf("device: %s\n", devicePtr);
2610    
2611     if (!strncmp(devicePtr, device, strlen(device))) {
2612        devicePtr += strlen(device);
2613        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2614            devicePtr++;
2615    
2616        *bootPtr = strdup(devicePtr);
2617        break;
2618     }
2619      }      }
2620    
2621      printf("kernel=%s\n", line->elements[1].item);      free(line);
2622        fclose(deviceMap);
2623        return 0;
2624    }
2625    
2626      if (line->numElements >= 3) {  int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2627   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);  
     }  
2628    
2629      i++;      if (suseGrubConfGetInstallDevice(path, &grubDevice))
2630   }   dbgPrintf("error looking for grub installation device\n");
2631   printf("\"\n");      else
2632      } else {   dbgPrintf("grubby installation device: %s\n", grubDevice);
  line = getLineByType(LT_KERNELARGS, entry->lines);  
  if (line) {  
     char * s;  
2633    
2634      printf("args=\"");      if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2635      i = 1;   dbgPrintf("error looking for grub boot device\n");
2636      while (i < line->numElements) {      else
2637   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;  
2638    
2639      printf("%s%s", s, line->elements[i].indent);      free(grubDevice);
2640   }      return 0;
2641    }
2642    
2643   i++;  int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2644      }      /*
2645         * This SuSE grub configuration file at this location is not your average
2646         * grub configuration file, but instead the grub commands used to setup
2647         * grub on that system.
2648         */
2649        const char * path;
2650        const static char default_path[] = "/etc/grub.conf";
2651    
2652      s = line->elements[i - 1].indent;      if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2653      printf("\"\n");   path = default_path;
  }  
     }  
2654    
2655      if (!root) {      if (!isSuseGrubConf(path)) return 1;
  line = getLineByType(LT_ROOT, entry->lines);  
  if (line && line->numElements >= 2)  
     root=line->elements[1].item;  
     }  
2656    
2657      if (root) {      if (lbaPtr) {
2658   char * s = alloca(strlen(root) + 1);          *lbaPtr = 0;
2659            if (suseGrubConfGetLba(path, lbaPtr))
2660   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);  
2661      }      }
2662    
2663      line = getLineByType(LT_INITRD, entry->lines);      if (bootPtr) {
2664            *bootPtr = NULL;
2665      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");  
2666      }      }
2667    
2668        return 0;
2669  }  }
2670    
2671  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1660  int parseSysconfigGrub(int * lbaPtr, cha Line 2716  int parseSysconfigGrub(int * lbaPtr, cha
2716  }  }
2717    
2718  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2719      char * boot;      char * boot = NULL;
2720      int lba;      int lba;
2721    
2722      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2723   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2724   if (boot) printf("boot=%s\n", boot);      free(boot);
2725        return;
2726     }
2727        } else {
2728            if (parseSysconfigGrub(&lba, &boot)) {
2729        free(boot);
2730        return;
2731     }
2732        }
2733    
2734        if (lba) printf("lba\n");
2735        if (boot) {
2736     printf("boot=%s\n", boot);
2737     free(boot);
2738      }      }
2739  }  }
2740    
# Line 1714  struct singleLine * addLineTmpl(struct s Line 2783  struct singleLine * addLineTmpl(struct s
2783  {  {
2784      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2785    
2786        if (isEfi && cfi == &grub2ConfigType) {
2787     enum lineType_e old = newLine->type;
2788     newLine->type = preferredLineType(newLine->type, cfi);
2789     if (old != newLine->type)
2790        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2791        }
2792    
2793      if (val) {      if (val) {
2794   /* override the inherited value with our own.   /* override the inherited value with our own.
2795   * 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 1723  struct singleLine * addLineTmpl(struct s Line 2799  struct singleLine * addLineTmpl(struct s
2799   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2800    
2801   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2802   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)) {
2803      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2804      if (rootspec != NULL) {      if (rootspec != NULL) {
2805   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 1760  struct singleLine *  addLine(struct sing Line 2836  struct singleLine *  addLine(struct sing
2836      /* 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
2837       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2838       */       */
   
2839      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2840   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2841   tmpl.type = type;   tmpl.type = type;
# Line 1770  struct singleLine *  addLine(struct sing Line 2845  struct singleLine *  addLine(struct sing
2845   sprintf(tmpl.elements[0].item, "[%s]", val);   sprintf(tmpl.elements[0].item, "[%s]", val);
2846   tmpl.elements[0].indent = "";   tmpl.elements[0].indent = "";
2847   val = NULL;   val = NULL;
2848        } else if (type == LT_MENUENTRY) {
2849     char *lineend = "--class gnu-linux --class gnu --class os {";
2850     if (!val) {
2851        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2852        abort();
2853     }
2854     kw = getKeywordByType(type, cfi);
2855     if (!kw) {
2856        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2857        abort();
2858     }
2859     tmpl.indent = "";
2860     tmpl.type = type;
2861     tmpl.numElements = 3;
2862     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2863     tmpl.elements[0].item = kw->key;
2864     tmpl.elements[0].indent = alloca(2);
2865     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2866     tmpl.elements[1].item = (char *)val;
2867     tmpl.elements[1].indent = alloca(2);
2868     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2869     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2870     strcpy(tmpl.elements[2].item, lineend);
2871     tmpl.elements[2].indent = "";
2872      } else {      } else {
2873   kw = getKeywordByType(type, cfi);   kw = getKeywordByType(type, cfi);
2874   if (!kw) abort();   if (!kw) {
2875        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2876        abort();
2877     }
2878   tmpl.type = type;   tmpl.type = type;
2879   tmpl.numElements = val ? 2 : 1;   tmpl.numElements = val ? 2 : 1;
2880   tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);   tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
# Line 1796  struct singleLine *  addLine(struct sing Line 2898  struct singleLine *  addLine(struct sing
2898   if (!line->next && !prev) prev = line;   if (!line->next && !prev) prev = line;
2899      }      }
2900    
2901      if (prev == entry->lines)      struct singleLine *menuEntry;
2902   tmpl.indent = defaultIndent ?: "";      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2903      else      if (tmpl.type == LT_ENTRY_END) {
2904   tmpl.indent = prev->indent;   if (menuEntry)
2905        tmpl.indent = menuEntry->indent;
2906     else
2907        tmpl.indent = defaultIndent ?: "";
2908        } else if (tmpl.type != LT_MENUENTRY) {
2909     if (menuEntry)
2910        tmpl.indent = "\t";
2911     else if (prev == entry->lines)
2912        tmpl.indent = defaultIndent ?: "";
2913     else
2914        tmpl.indent = prev->indent;
2915        }
2916    
2917      return addLineTmpl(entry, &tmpl, prev, val, cfi);      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2918  }  }
# Line 1826  void removeLine(struct singleEntry * ent Line 2939  void removeLine(struct singleEntry * ent
2939      free(line);      free(line);
2940  }  }
2941    
2942    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2943    {
2944        struct singleLine newLine = {
2945     .indent = tmplLine->indent,
2946     .type = tmplLine->type,
2947     .next = tmplLine->next,
2948        };
2949        int firstQuotedItem = -1;
2950        int quoteLen = 0;
2951        int j;
2952        int element = 0;
2953        char *c;
2954    
2955        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2956        strcpy(c, tmplLine->elements[0].item);
2957        insertElement(&newLine, c, element++, cfi);
2958        free(c);
2959        c = NULL;
2960    
2961        for (j = 1; j < tmplLine->numElements; j++) {
2962     if (firstQuotedItem == -1) {
2963        quoteLen += strlen(tmplLine->elements[j].item);
2964        
2965        if (isquote(tmplLine->elements[j].item[0])) {
2966     firstQuotedItem = j;
2967            quoteLen += strlen(tmplLine->elements[j].indent);
2968        } else {
2969     c = malloc(quoteLen + 1);
2970     strcpy(c, tmplLine->elements[j].item);
2971     insertElement(&newLine, c, element++, cfi);
2972     free(c);
2973     quoteLen = 0;
2974        }
2975     } else {
2976        int itemlen = strlen(tmplLine->elements[j].item);
2977        quoteLen += itemlen;
2978        quoteLen += strlen(tmplLine->elements[j].indent);
2979        
2980        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2981     c = malloc(quoteLen + 1);
2982     c[0] = '\0';
2983     for (int i = firstQuotedItem; i < j+1; i++) {
2984        strcat(c, tmplLine->elements[i].item);
2985        strcat(c, tmplLine->elements[i].indent);
2986     }
2987     insertElement(&newLine, c, element++, cfi);
2988     free(c);
2989    
2990     firstQuotedItem = -1;
2991     quoteLen = 0;
2992        }
2993     }
2994        }
2995        while (tmplLine->numElements)
2996     removeElement(tmplLine, 0);
2997        if (tmplLine->elements)
2998     free(tmplLine->elements);
2999    
3000        tmplLine->numElements = newLine.numElements;
3001        tmplLine->elements = newLine.elements;
3002    }
3003    
3004  static void insertElement(struct singleLine * line,  static void insertElement(struct singleLine * line,
3005    const char * item, int insertHere,    const char * item, int insertHere,
3006    struct configFileInfo * cfi)    struct configFileInfo * cfi)
# Line 1994  int updateActualImage(struct grubConfig Line 3169  int updateActualImage(struct grubConfig
3169      firstElement = 2;      firstElement = 2;
3170    
3171   } else {   } else {
3172      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3173      if (!line) {      if (!line) {
3174   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3175   continue;   continue;
# Line 2150  int updateImage(struct grubConfig * cfg, Line 3325  int updateImage(struct grubConfig * cfg,
3325      return rc;      return rc;
3326  }  }
3327    
3328    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3329     const char * image, const char * prefix, const char * initrd,
3330     const char * title) {
3331        struct singleEntry * entry;
3332        struct singleLine * line, * kernelLine, *endLine = NULL;
3333        int index = 0;
3334    
3335        if (!image) return 0;
3336    
3337        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3338            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3339            if (!kernelLine) continue;
3340    
3341     /* if title is supplied, the entry's title must match it. */
3342     if (title) {
3343        char *linetitle;
3344    
3345        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3346        if (!line)
3347     continue;
3348    
3349        linetitle = extractTitle(cfg, line);
3350        if (!linetitle)
3351     continue;
3352        if (strcmp(title, linetitle)) {
3353     free(linetitle);
3354     continue;
3355        }
3356        free(linetitle);
3357     }
3358    
3359            if (prefix) {
3360                int prefixLen = strlen(prefix);
3361                if (!strncmp(initrd, prefix, prefixLen))
3362                    initrd += prefixLen;
3363            }
3364     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3365     if (endLine)
3366        removeLine(entry, endLine);
3367            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3368     kernelLine->indent, initrd);
3369            if (!line)
3370        return 1;
3371     if (endLine) {
3372        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3373                if (!line)
3374     return 1;
3375     }
3376    
3377            break;
3378        }
3379    
3380        return 0;
3381    }
3382    
3383  int updateInitrd(struct grubConfig * cfg, const char * image,  int updateInitrd(struct grubConfig * cfg, const char * image,
3384                   const char * prefix, const char * initrd) {                   const char * prefix, const char * initrd, const char * title) {
3385      struct singleEntry * entry;      struct singleEntry * entry;
3386      struct singleLine * line, * kernelLine;      struct singleLine * line, * kernelLine, *endLine = NULL;
3387      int index = 0;      int index = 0;
3388    
3389      if (!image) return 0;      if (!image) return 0;
3390    
3391      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3392          kernelLine = getLineByType(LT_KERNEL, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3393          if (!kernelLine) continue;          if (!kernelLine) continue;
3394    
3395          line = getLineByType(LT_INITRD, entry->lines);   /* if title is supplied, the entry's title must match it. */
3396     if (title) {
3397        char *linetitle;
3398    
3399        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3400        if (!line)
3401     continue;
3402    
3403        linetitle = extractTitle(cfg, line);
3404        if (!linetitle)
3405     continue;
3406        if (strcmp(title, linetitle)) {
3407     free(linetitle);
3408     continue;
3409        }
3410        free(linetitle);
3411     }
3412    
3413            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3414          if (line)          if (line)
3415              removeLine(entry, line);              removeLine(entry, line);
3416          if (prefix) {          if (prefix) {
# Line 2170  int updateInitrd(struct grubConfig * cfg Line 3418  int updateInitrd(struct grubConfig * cfg
3418              if (!strncmp(initrd, prefix, prefixLen))              if (!strncmp(initrd, prefix, prefixLen))
3419                  initrd += prefixLen;                  initrd += prefixLen;
3420          }          }
3421          line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3422          if (!line) return 1;   if (endLine)
3423        removeLine(entry, endLine);
3424     enum lineType_e lt;
3425     switch(kernelLine->type) {
3426        case LT_KERNEL:
3427            lt = LT_INITRD;
3428     break;
3429        case LT_KERNEL_EFI:
3430            lt = LT_INITRD_EFI;
3431     break;
3432        case LT_KERNEL_16:
3433            lt = LT_INITRD_16;
3434     break;
3435        default:
3436            lt = preferredLineType(LT_INITRD, cfg->cfi);
3437     }
3438            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3439            if (!line)
3440        return 1;
3441     if (endLine) {
3442        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3443                if (!line)
3444     return 1;
3445     }
3446    
3447          break;          break;
3448      }      }
3449    
# Line 2201  int checkDeviceBootloader(const char * d Line 3473  int checkDeviceBootloader(const char * d
3473      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3474   return 0;   return 0;
3475    
3476      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3477   offset = boot[2] + 2;   offset = boot[2] + 2;
3478      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3479   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3480      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3481   offset = boot[1] + 2;        offset = boot[1] + 2;
3482            /*
3483     * it looks like grub, when copying stage1 into the mbr, patches stage1
3484     * right after the JMP location, replacing other instructions such as
3485     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3486     * different bytes.
3487     */
3488          if ((bootSect[offset + 1] == NOOP_OPCODE)
3489      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3490     offset = offset + 3;
3491          }
3492      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3493   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3494      } else {      } else {
# Line 2348  int checkForLilo(struct grubConfig * con Line 3630  int checkForLilo(struct grubConfig * con
3630      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3631  }  }
3632    
3633    int checkForGrub2(struct grubConfig * config) {
3634        if (!access("/etc/grub.d/", R_OK))
3635     return 2;
3636    
3637        return 1;
3638    }
3639    
3640  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3641      int fd;      int fd;
3642      unsigned char bootSect[512];      unsigned char bootSect[512];
3643      char * boot;      char * boot;
3644        int onSuse = isSuseSystem();
3645    
3646      if (parseSysconfigGrub(NULL, &boot))  
3647   return 0;      if (onSuse) {
3648     if (parseSuseGrubConf(NULL, &boot))
3649        return 0;
3650        } else {
3651     if (parseSysconfigGrub(NULL, &boot))
3652        return 0;
3653        }
3654    
3655      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3656      if (!boot)      if (!boot)
# Line 2373  int checkForGrub(struct grubConfig * con Line 3669  int checkForGrub(struct grubConfig * con
3669      }      }
3670      close(fd);      close(fd);
3671    
3672        /* The more elaborate checks do not work on SuSE. The checks done
3673         * seem to be reasonble (at least for now), so just return success
3674         */
3675        if (onSuse)
3676     return 2;
3677    
3678      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3679  }  }
3680    
# Line 2406  int checkForExtLinux(struct grubConfig * Line 3708  int checkForExtLinux(struct grubConfig *
3708      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3709  }  }
3710    
3711    int checkForYaboot(struct grubConfig * config) {
3712        /*
3713         * This is a simplistic check that we consider good enough for own puporses
3714         *
3715         * If we were to properly check if yaboot is *installed* we'd need to:
3716         * 1) get the system boot device (LT_BOOT)
3717         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3718         *    the content on the boot device
3719         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3720         * 4) check again if binary and boot device contents match
3721         */
3722        if (!access("/etc/yaboot.conf", R_OK))
3723     return 2;
3724    
3725        return 1;
3726    }
3727    
3728    int checkForElilo(struct grubConfig * config) {
3729        if (!access("/etc/elilo.conf", R_OK))
3730     return 2;
3731    
3732        return 1;
3733    }
3734    
3735  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3736      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3737    
# Line 2420  static char * getRootSpecifier(char * st Line 3746  static char * getRootSpecifier(char * st
3746  static char * getInitrdVal(struct grubConfig * config,  static char * getInitrdVal(struct grubConfig * config,
3747     const char * prefix, struct singleLine *tmplLine,     const char * prefix, struct singleLine *tmplLine,
3748     const char * newKernelInitrd,     const char * newKernelInitrd,
3749     char ** extraInitrds, int extraInitrdCount)     const char ** extraInitrds, int extraInitrdCount)
3750  {  {
3751      char *initrdVal, *end;      char *initrdVal, *end;
3752      int i;      int i;
# Line 2465  static char * getInitrdVal(struct grubCo Line 3791  static char * getInitrdVal(struct grubCo
3791    
3792  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3793           const char * prefix,           const char * prefix,
3794   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3795   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3796   char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3797                   char * newMBKernel, char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3798     const char * newDevTreePath) {
3799      struct singleEntry * new;      struct singleEntry * new;
3800      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3801      int needs;      int needs;
# Line 2509  int addNewKernel(struct grubConfig * con Line 3836  int addNewKernel(struct grubConfig * con
3836          needs |= NEED_MB;          needs |= NEED_MB;
3837          new->multiboot = 1;          new->multiboot = 1;
3838      }      }
3839        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3840     needs |= NEED_DEVTREE;
3841    
3842      if (template) {      if (template) {
3843   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 2522  int addNewKernel(struct grubConfig * con Line 3851  int addNewKernel(struct grubConfig * con
3851      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3852      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3853    
3854      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
  tmplLine->numElements >= 2) {  
3855   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3856      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3857       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 2600  int addNewKernel(struct grubConfig * con Line 3928  int addNewKernel(struct grubConfig * con
3928      /* template is multi but new is not,      /* template is multi but new is not,
3929       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3930       */       */
3931      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3932      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3933      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3934   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3935     config->cfi)->key);
3936      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3937    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3938      config->cfi);
3939      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3940   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3941      char *initrdVal;      char *initrdVal;
3942      /* template is multi but new is not,      /* template is multi but new is not,
3943       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3944       */       */
3945      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3946      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3947      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3948   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3949     config->cfi)->key);
3950      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3951      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3952      free(initrdVal);      free(initrdVal);
3953      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3954   }   }
3955    
3956      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3957   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3958      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3959      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 2649  int addNewKernel(struct grubConfig * con Line 3979  int addNewKernel(struct grubConfig * con
3979      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3980   }   }
3981    
3982        } else if (tmplLine->type == LT_MENUENTRY &&
3983           (needs & NEED_TITLE)) {
3984     requote(tmplLine, config->cfi);
3985     char *nkt = malloc(strlen(newKernelTitle)+3);
3986     strcpy(nkt, "'");
3987     strcat(nkt, newKernelTitle);
3988     strcat(nkt, "'");
3989     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3990     free(nkt);
3991     needs &= ~NEED_TITLE;
3992      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3993         (needs & NEED_TITLE)) {         (needs & NEED_TITLE)) {
3994   if (tmplLine->numElements >= 2) {   if (tmplLine->numElements >= 2) {
# Line 2662  int addNewKernel(struct grubConfig * con Line 4002  int addNewKernel(struct grubConfig * con
4002        tmplLine->indent, newKernelTitle);        tmplLine->indent, newKernelTitle);
4003      needs &= ~NEED_TITLE;      needs &= ~NEED_TITLE;
4004   }   }
4005        } else if (tmplLine->type == LT_ECHO) {
4006        requote(tmplLine, config->cfi);
4007        static const char *prefix = "'Loading ";
4008        if (tmplLine->numElements > 1 &&
4009        strstr(tmplLine->elements[1].item, prefix) &&
4010        masterLine->next &&
4011        iskernel(masterLine->next->type)) {
4012     char *newTitle = malloc(strlen(prefix) +
4013     strlen(newKernelTitle) + 2);
4014    
4015     strcpy(newTitle, prefix);
4016     strcat(newTitle, newKernelTitle);
4017     strcat(newTitle, "'");
4018     newLine = addLine(new, config->cfi, LT_ECHO,
4019     tmplLine->indent, newTitle);
4020     free(newTitle);
4021        } else {
4022     /* pass through other lines from the template */
4023     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
4024     config->cfi);
4025        }
4026        } else if (tmplLine->type == LT_DEVTREE &&
4027           tmplLine->numElements == 2 && newDevTreePath) {
4028            newLine = addLineTmpl(new, tmplLine, newLine,
4029          newDevTreePath + strlen(prefix),
4030          config->cfi);
4031     needs &= ~NEED_DEVTREE;
4032        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
4033     const char *ndtp = newDevTreePath;
4034     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
4035        ndtp += strlen(prefix);
4036     newLine = addLine(new, config->cfi, LT_DEVTREE,
4037      config->secondaryIndent,
4038      ndtp);
4039     needs &= ~NEED_DEVTREE;
4040     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4041      } else {      } else {
4042   /* pass through other lines from the template */   /* pass through other lines from the template */
4043   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 2675  int addNewKernel(struct grubConfig * con Line 4050  int addNewKernel(struct grubConfig * con
4050   */   */
4051   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
4052      case LT_KERNEL:      case LT_KERNEL:
4053        case LT_KERNEL_EFI:
4054        case LT_KERNEL_16:
4055   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
4056      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
4057   } else {   } else {
4058      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
4059              preferredLineType(LT_KERNEL, config->cfi),
4060        config->primaryIndent,        config->primaryIndent,
4061        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
4062      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 2692  int addNewKernel(struct grubConfig * con Line 4070  int addNewKernel(struct grubConfig * con
4070   needs &= ~NEED_MB;   needs &= ~NEED_MB;
4071   break;   break;
4072    
4073        case LT_MENUENTRY: {
4074     char *nkt = malloc(strlen(newKernelTitle)+3);
4075     strcpy(nkt, "'");
4076     strcat(nkt, newKernelTitle);
4077     strcat(nkt, "'");
4078            newLine = addLine(new, config->cfi, LT_MENUENTRY,
4079      config->primaryIndent, nkt);
4080     free(nkt);
4081     needs &= ~NEED_TITLE;
4082     needs |= NEED_END;
4083     break;
4084        }
4085      case LT_TITLE:      case LT_TITLE:
4086   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)
4087   char * templabel;   char * templabel;
# Line 2723  int addNewKernel(struct grubConfig * con Line 4113  int addNewKernel(struct grubConfig * con
4113   }   }
4114      }      }
4115    
4116        struct singleLine *endLine = NULL;
4117        endLine = getLineByType(LT_ENTRY_END, new->lines);
4118        if (endLine) {
4119        removeLine(new, endLine);
4120        needs |= NEED_END;
4121        }
4122    
4123      /* add the remainder of the lines, i.e. those that either      /* add the remainder of the lines, i.e. those that either
4124       * 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,
4125       * all the lines following the entryStart.       * all the lines following the entryStart.
# Line 2742  int addNewKernel(struct grubConfig * con Line 4139  int addNewKernel(struct grubConfig * con
4139      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
4140   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4141    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4142        config->cfi)) ?        config->cfi))
4143    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
4144     : preferredLineType(LT_KERNEL, config->cfi),
4145    config->secondaryIndent,    config->secondaryIndent,
4146    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
4147   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 2759  int addNewKernel(struct grubConfig * con Line 4157  int addNewKernel(struct grubConfig * con
4157   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4158   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4159    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4160        config->cfi)) ?        config->cfi))
4161    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
4162       : preferredLineType(LT_INITRD, config->cfi),
4163    config->secondaryIndent,    config->secondaryIndent,
4164    initrdVal);    initrdVal);
4165   free(initrdVal);   free(initrdVal);
4166   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4167      }      }
4168        if (needs & NEED_DEVTREE) {
4169     newLine = addLine(new, config->cfi, LT_DEVTREE,
4170      config->secondaryIndent,
4171      newDevTreePath);
4172     needs &= ~NEED_DEVTREE;
4173        }
4174    
4175        /* NEEDS_END must be last on bootloaders that need it... */
4176        if (needs & NEED_END) {
4177     newLine = addLine(new, config->cfi, LT_ENTRY_END,
4178     config->secondaryIndent, NULL);
4179     needs &= ~NEED_END;
4180        }
4181    
4182      if (needs) {      if (needs) {
4183   printf(_("grubby: needs=%d, aborting\n"), needs);   printf(_("grubby: needs=%d, aborting\n"), needs);
# Line 2787  static void traceback(int signum) Line 4199  static void traceback(int signum)
4199      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
4200      size = backtrace(array, 40);      size = backtrace(array, 40);
4201    
4202      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4203              (unsigned long)size);              (unsigned long)size);
4204      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
4205      exit(1);      exit(1);
# Line 2795  static void traceback(int signum) Line 4207  static void traceback(int signum)
4207    
4208  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
4209      poptContext optCon;      poptContext optCon;
4210      char * grubConfig = NULL;      const char * grubConfig = NULL;
4211      char * outputFile = NULL;      char * outputFile = NULL;
4212      int arg = 0;      int arg = 0;
4213      int flags = 0;      int flags = 0;
4214      int badImageOkay = 0;      int badImageOkay = 0;
4215        int configureGrub2 = 0;
4216      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
4217      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
4218      int configureExtLinux = 0;      int configureExtLinux = 0;
# Line 2811  int main(int argc, const char ** argv) { Line 4224  int main(int argc, const char ** argv) {
4224      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4225      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4226      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4227      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4228      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4229      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4230      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 2821  int main(int argc, const char ** argv) { Line 4234  int main(int argc, const char ** argv) {
4234      char * removeArgs = NULL;      char * removeArgs = NULL;
4235      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4236      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4237        char * envPath = NULL;
4238      const char * chptr = NULL;      const char * chptr = NULL;
4239      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4240      struct grubConfig * config;      struct grubConfig * config;
4241      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4242      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4243      int displayDefault = 0;      int displayDefault = 0;
4244        int displayDefaultIndex = 0;
4245        int displayDefaultTitle = 0;
4246        int defaultIndex = -1;
4247      struct poptOption options[] = {      struct poptOption options[] = {
4248   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4249      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2844  int main(int argc, const char ** argv) { Line 4261  int main(int argc, const char ** argv) {
4261   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4262      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4263      _("bootfs") },      _("bootfs") },
4264  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4265   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4266      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4267  #endif  #endif
4268   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4269      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 2857  int main(int argc, const char ** argv) { Line 4274  int main(int argc, const char ** argv) {
4274        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4275        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4276        "template"), NULL },        "template"), NULL },
4277     { "debug", 0, 0, &debug, 0,
4278        _("print debugging information for failures") },
4279   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4280      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4281     { "default-index", 0, 0, &displayDefaultIndex, 0,
4282        _("display the index of the default kernel") },
4283     { "default-title", 0, 0, &displayDefaultTitle, 0,
4284        _("display the title of the default kernel") },
4285     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4286        _("device tree file for new stanza"), _("dtb-path") },
4287     { "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4288        _("device tree directory for new stanza"), _("dtb-path") },
4289   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4290      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4291     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4292        _("force grub2 stanzas to use efi") },
4293     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4294        _("path for environment data"),
4295        _("path") },
4296   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4297      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4298   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
4299      _("configure grub bootloader") },      _("configure grub bootloader") },
4300     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
4301        _("configure grub2 bootloader") },
4302   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
4303      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
4304      _("kernel-path") },      _("kernel-path") },
4305   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4306      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4307   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4308      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4309   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4310      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4311   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2891  int main(int argc, const char ** argv) { Line 4325  int main(int argc, const char ** argv) {
4325   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4326      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4327        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4328     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4329        _("make the given entry index the default entry"),
4330        _("entry-index") },
4331   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4332      _("configure silo bootloader") },      _("configure silo bootloader") },
4333   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2912  int main(int argc, const char ** argv) { Line 4349  int main(int argc, const char ** argv) {
4349    
4350      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4351    
4352        int i = 0;
4353        for (int j = 1; j < argc; j++)
4354     i += strlen(argv[j]) + 1;
4355        saved_command_line = malloc(i);
4356        if (!saved_command_line) {
4357     fprintf(stderr, "grubby: %m\n");
4358     exit(1);
4359        }
4360        saved_command_line[0] = '\0';
4361        for (int j = 1; j < argc; j++) {
4362     strcat(saved_command_line, argv[j]);
4363     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4364        }
4365    
4366      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4367      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4368    
# Line 2944  int main(int argc, const char ** argv) { Line 4395  int main(int argc, const char ** argv) {
4395   return 1;   return 1;
4396      }      }
4397    
4398      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
4399   configureYaboot + configureSilo + configureZipl +   configureYaboot + configureSilo + configureZipl +
4400   configureExtLinux ) > 1) {   configureExtLinux ) > 1) {
4401   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
# Line 2953  int main(int argc, const char ** argv) { Line 4404  int main(int argc, const char ** argv) {
4404   fprintf(stderr,   fprintf(stderr,
4405      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
4406   return 1;   return 1;
4407        } else if (configureGrub2) {
4408     cfi = &grub2ConfigType;
4409     if (envPath)
4410        cfi->envFile = envPath;
4411      } else if (configureLilo) {      } else if (configureLilo) {
4412   cfi = &liloConfigType;   cfi = &liloConfigType;
4413      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2971  int main(int argc, const char ** argv) { Line 4426  int main(int argc, const char ** argv) {
4426      }      }
4427    
4428      if (!cfi) {      if (!cfi) {
4429            if (grub2FindConfig(&grub2ConfigType))
4430        cfi = &grub2ConfigType;
4431     else
4432        #ifdef __ia64__        #ifdef __ia64__
4433   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4434        #elif __powerpc__        #elif __powerpc__
4435   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4436        #elif __sparc__        #elif __sparc__
4437          cfi = &siloConfigType;              cfi = &siloConfigType;
4438        #elif __s390__        #elif __s390__
4439          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4440        #elif __s390x__        #elif __s390x__
4441          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4442        #else        #else
4443   cfi = &grubConfigType;      cfi = &grubConfigType;
4444        #endif        #endif
4445      }      }
4446    
4447      if (!grubConfig)      if (!grubConfig) {
4448   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4449        grubConfig = cfi->findConfig(cfi);
4450     if (!grubConfig)
4451        grubConfig = cfi->defaultConfig;
4452        }
4453    
4454      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4455    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4456    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4457        (defaultIndex >= 0))) {
4458   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4459    "specified option"));    "specified option"));
4460   return 1;   return 1;
4461      }      }
4462    
4463      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4464     removeKernelPath)) {     removeKernelPath)) {
4465   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4466    "be used when adding or removing kernels\n"));    "be used when adding or removing kernels\n"));
# Line 3007  int main(int argc, const char ** argv) { Line 4470  int main(int argc, const char ** argv) {
4470      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4471   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4472   return 1;   return 1;
4473      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||      } else if (!newKernelPath && (copyDefault ||
4474    (newKernelInitrd && !updateKernelPath)||    (newKernelInitrd && !updateKernelPath)||
4475    makeDefault || extraInitrdCount > 0)) {    makeDefault || extraInitrdCount > 0)) {
4476   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
# Line 3033  int main(int argc, const char ** argv) { Line 4496  int main(int argc, const char ** argv) {
4496   makeDefault = 1;   makeDefault = 1;
4497   defaultKernel = NULL;   defaultKernel = NULL;
4498      }      }
4499        else if (defaultKernel && (defaultIndex >= 0)) {
4500     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4501      "may not be used together\n"));
4502     return 1;
4503        }
4504    
4505      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4506   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4507   "is used\n"));   "is used\n"));
4508   return 1;   return 1;
4509      }      }
4510    
4511      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4512   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4513          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4514     && (defaultIndex == -1)) {
4515   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4516   return 1;   return 1;
4517      }      }
# Line 3069  int main(int argc, const char ** argv) { Line 4538  int main(int argc, const char ** argv) {
4538      }      }
4539    
4540      if (bootloaderProbe) {      if (bootloaderProbe) {
4541   int lrc = 0, grc = 0, erc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4542   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4543    
4544     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4545     if (grub2config) {
4546        gconfig = readConfig(grub2config, &grub2ConfigType);
4547        if (!gconfig)
4548     gr2c = 1;
4549        else
4550     gr2c = checkForGrub2(gconfig);
4551     }
4552    
4553   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4554      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4555        gconfig = readConfig(grubconfig, &grubConfigType);
4556      if (!gconfig)      if (!gconfig)
4557   grc = 1;   grc = 1;
4558      else      else
# Line 3088  int main(int argc, const char ** argv) { Line 4567  int main(int argc, const char ** argv) {
4567   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4568   }   }
4569    
4570     if (!access(eliloConfigType.defaultConfig, F_OK)) {
4571        econfig = readConfig(eliloConfigType.defaultConfig,
4572     &eliloConfigType);
4573        if (!econfig)
4574     erc = 1;
4575        else
4576     erc = checkForElilo(econfig);
4577     }
4578    
4579   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4580      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4581      if (!lconfig)      if (!lconfig)
4582   erc = 1;   extrc = 1;
4583      else      else
4584   erc = checkForExtLinux(lconfig);   extrc = checkForExtLinux(lconfig);
4585   }   }
4586    
4587   if (lrc == 1 || grc == 1) return 1;  
4588     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4589        yconfig = readConfig(yabootConfigType.defaultConfig,
4590     &yabootConfigType);
4591        if (!yconfig)
4592     yrc = 1;
4593        else
4594     yrc = checkForYaboot(yconfig);
4595     }
4596    
4597     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4598     erc == 1)
4599        return 1;
4600    
4601   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4602     if (gr2c == 2) printf("grub2\n");
4603   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4604   if (erc == 2) printf("extlinux\n");   if (extrc == 2) printf("extlinux\n");
4605     if (yrc == 2) printf("yaboot\n");
4606     if (erc == 2) printf("elilo\n");
4607    
4608   return 0;   return 0;
4609      }      }
4610    
4611        if (grubConfig == NULL) {
4612     printf("Could not find bootloader configuration file.\n");
4613     exit(1);
4614        }
4615    
4616      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4617      if (!config) return 1;      if (!config) return 1;
4618    
# Line 3114  int main(int argc, const char ** argv) { Line 4622  int main(int argc, const char ** argv) {
4622          char * rootspec;          char * rootspec;
4623    
4624   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4625     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4626     cfi->defaultIsSaved)
4627        config->defaultImage = 0;
4628   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4629   if (!entry) return 0;   if (!entry) return 0;
4630   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4631    
4632   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
4633   if (!line) return 0;   if (!line) return 0;
4634    
4635          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 3126  int main(int argc, const char ** argv) { Line 4637  int main(int argc, const char ** argv) {
4637                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4638    
4639   return 0;   return 0;
4640    
4641        } else if (displayDefaultTitle) {
4642     struct singleLine * line;
4643     struct singleEntry * entry;
4644    
4645     if (config->defaultImage == -1) return 0;
4646     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4647     cfi->defaultIsSaved)
4648        config->defaultImage = 0;
4649     entry = findEntryByIndex(config, config->defaultImage);
4650     if (!entry) return 0;
4651    
4652     if (!configureGrub2) {
4653      line = getLineByType(LT_TITLE, entry->lines);
4654      if (!line) return 0;
4655      printf("%s\n", line->elements[1].item);
4656    
4657     } else {
4658      char * title;
4659    
4660      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4661      line = getLineByType(LT_MENUENTRY, entry->lines);
4662      if (!line) return 0;
4663      title = grub2ExtractTitle(line);
4664      if (title)
4665        printf("%s\n", title);
4666     }
4667     return 0;
4668    
4669        } else if (displayDefaultIndex) {
4670            if (config->defaultImage == -1) return 0;
4671     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4672     cfi->defaultIsSaved)
4673        config->defaultImage = 0;
4674            printf("%i\n", config->defaultImage);
4675            return 0;
4676    
4677      } else if (kernelInfo)      } else if (kernelInfo)
4678   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4679    
# Line 3137  int main(int argc, const char ** argv) { Line 4685  int main(int argc, const char ** argv) {
4685      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4686      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4687      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4688      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4689      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4690      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4691                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4692      if (updateKernelPath && newKernelInitrd) {      if (updateKernelPath && newKernelInitrd) {
4693              if (updateInitrd(config, updateKernelPath, bootPrefix,      if (newMBKernel) {
4694                               newKernelInitrd)) return 1;      if (addMBInitrd(config, newMBKernel, updateKernelPath,
4695     bootPrefix, newKernelInitrd,
4696     newKernelTitle))
4697        return 1;
4698        } else {
4699        if (updateInitrd(config, updateKernelPath, bootPrefix,
4700     newKernelInitrd, newKernelTitle))
4701     return 1;
4702        }
4703      }      }
4704      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4705                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4706                       extraInitrds, extraInitrdCount,                       (const char **)extraInitrds, extraInitrdCount,
4707                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4708            
4709    
4710      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {
# Line 3158  int main(int argc, const char ** argv) { Line 4714  int main(int argc, const char ** argv) {
4714      }      }
4715    
4716      if (!outputFile)      if (!outputFile)
4717   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4718    
4719      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4720  }  }

Legend:
Removed from v.1693  
changed lines
  Added in v.2980