Magellan Linux

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

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

revision 1849 by niro, Mon Jul 2 13:08:29 2012 UTC revision 2986 by niro, Thu Jun 30 10:30:31 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  #ifndef DEBUG
42  #define DEBUG 0  #define DEBUG 0
43  #endif  #endif
# Line 56  int debug = 0; /* Currently just for tem Line 58  int debug = 0; /* Currently just for tem
58  #define NOOP_OPCODE 0x90  #define NOOP_OPCODE 0x90
59  #define JMP_SHORT_OPCODE 0xeb  #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 82  enum lineType_e { Line 94  enum lineType_e {
94      LT_MENUENTRY    = 1 << 17,      LT_MENUENTRY    = 1 << 17,
95      LT_ENTRY_END    = 1 << 18,      LT_ENTRY_END    = 1 << 18,
96      LT_SET_VARIABLE = 1 << 19,      LT_SET_VARIABLE = 1 << 19,
97      LT_UNKNOWN      = 1 << 20,      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 111  struct singleEntry { Line 128  struct singleEntry {
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)  #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
# Line 128  struct configFileInfo; Line 146  struct configFileInfo;
146  typedef const char *(*findConfigFunc)(struct configFileInfo *);  typedef const char *(*findConfigFunc)(struct configFileInfo *);
147  typedef const int (*writeLineFunc)(struct configFileInfo *,  typedef const int (*writeLineFunc)(struct configFileInfo *,
148   struct singleLine *line);   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;      findConfigFunc findConfig;
155      writeLineFunc writeLine;      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;      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;      enum lineType_e entryEnd;
167      int needsBootPrefix;      int needsBootPrefix;
# Line 148  struct configFileInfo { Line 173  struct configFileInfo {
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 164  struct keywordTypes grubKeywords[] = { Line 190  struct keywordTypes grubKeywords[] = {
190    
191  const char *grubFindConfig(struct configFileInfo *cfi) {  const char *grubFindConfig(struct configFileInfo *cfi) {
192      static const char *configFiles[] = {      static const char *configFiles[] = {
  "/etc/grub.conf",  
193   "/boot/grub/grub.conf",   "/boot/grub/grub.conf",
194   "/boot/grub/menu.lst",   "/boot/grub/menu.lst",
195     "/etc/grub.conf",
196     "/boot/grub2/grub.cfg",
197     "/boot/grub2-efi/grub.cfg",
198   NULL   NULL
199      };      };
200      static int i = -1;      static int i = -1;
# Line 194  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[] = {  struct keywordTypes grub2Keywords[] = {
# Line 205  struct keywordTypes grub2Keywords[] = { Line 234  struct keywordTypes grub2Keywords[] = {
234      { "default",    LT_DEFAULT,     ' ' },      { "default",    LT_DEFAULT,     ' ' },
235      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
236      { "linux",      LT_KERNEL,      ' ' },      { "linux",      LT_KERNEL,      ' ' },
237        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
238        { "linux16",    LT_KERNEL_16,   ' ' },
239      { "initrd",     LT_INITRD,      ' ', ' ' },      { "initrd",     LT_INITRD,      ' ', ' ' },
240        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
241        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
242      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
243      { "kernel",     LT_HYPER,       ' ' },      { "kernel",     LT_HYPER,       ' ' },
244        { "devicetree", LT_DEVTREE,  ' ' },
245      { NULL, 0, 0 },      { NULL, 0, 0 },
246  };  };
247    
# Line 219  const char *grub2FindConfig(struct confi Line 253  const char *grub2FindConfig(struct confi
253      };      };
254      static int i = -1;      static int i = -1;
255      static const char *grub_cfg = "/boot/grub/grub.cfg";      static const char *grub_cfg = "/boot/grub/grub.cfg";
256        int rc = -1;
257    
258      if (i == -1) {      if (i == -1) {
259   for (i = 0; configFiles[i] != NULL; i++) {   for (i = 0; configFiles[i] != NULL; i++) {
260      dbgPrintf("Checking \"%s\": ", configFiles[i]);      dbgPrintf("Checking \"%s\": ", configFiles[i]);
261      if (!access(configFiles[i], R_OK)) {      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");   dbgPrintf("found\n");
270   return configFiles[i];   return configFiles[i];
271      }      }
# Line 242  const char *grub2FindConfig(struct confi Line 284  const char *grub2FindConfig(struct confi
284      return configFiles[i];      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) {  int sizeOfSingleLine(struct singleLine * line) {
387    int count = 0;    int count = 0;
388    
# Line 271  static int isquote(char q) Line 412  static int isquote(char q)
412      return 0;      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) {  char *grub2ExtractTitle(struct singleLine * line) {
424      char * current;      char * current;
425      char * current_indent;      char * current_indent;
# Line 328  char *grub2ExtractTitle(struct singleLin Line 477  char *grub2ExtractTitle(struct singleLin
477    
478  struct configFileInfo grub2ConfigType = {  struct configFileInfo grub2ConfigType = {
479      .findConfig = grub2FindConfig,      .findConfig = grub2FindConfig,
480        .getEnv = grub2GetEnv,
481        .setEnv = grub2SetEnv,
482      .keywords = grub2Keywords,      .keywords = grub2Keywords,
483      .defaultIsIndex = 1,      .defaultIsIndex = 1,
484      .defaultSupportSaved = 1,      .defaultSupportSaved = 1,
# Line 432  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 442  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 450  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 460  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 469  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 482  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 506  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 570  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      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
# Line 603  static char * getuuidbydev(char *device) Line 791  static char * getuuidbydev(char *device)
791  static enum lineType_e getTypeByKeyword(char * keyword,  static enum lineType_e getTypeByKeyword(char * keyword,
792   struct configFileInfo * cfi) {   struct configFileInfo * cfi) {
793      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
794   if (!strcmp(keyword, kw->key))   if (cfi->caseInsensitive) {
795      return kw->type;      if (!strcasecmp(keyword, kw->key))
796                    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 641  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 (line->type == LT_TITLE) {
841      title++;   char *tmp = line->elements[cfg->cfi->titlePosition].item;
842      *(title + strlen(title) - 1) = '\0';   if (cfg->cfi->titleBracketed) {
843        tmp++;
844        title = strdup(tmp);
845        *(title + strlen(title) - 1) = '\0';
846     } else {
847        title = strdup(tmp);
848     }
849        } else if (line->type == LT_MENUENTRY)
850     title = strdup(line->elements[1].item);
851        else
852     return NULL;
853      return title;      return title;
854  }  }
855    
# Line 904  static int getNextLine(char ** bufPtr, s Line 1107  static int getNextLine(char ** bufPtr, s
1107      return 0;      return 0;
1108  }  }
1109    
1110    static int isnumber(const char *s)
1111    {
1112        int i;
1113        for (i = 0; s[i] != '\0'; i++)
1114     if (s[i] < '0' || s[i] > '9')
1115        return 0;
1116        return i;
1117    }
1118    
1119  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1120        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1121      int in;      int in;
# Line 918  static struct grubConfig * readConfig(co Line 1130  static struct grubConfig * readConfig(co
1130      int len;      int len;
1131      char * buf;      char * buf;
1132    
1133      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1134            printf("Could not find bootloader configuration\n");
1135            exit(1);
1136        } else if (!strcmp(inName, "-")) {
1137   in = 0;   in = 0;
1138      } else {      } else {
1139   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 985  static struct grubConfig * readConfig(co Line 1200  static struct grubConfig * readConfig(co
1200      dbgPrintf("\n");      dbgPrintf("\n");
1201      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1202      if (kwType && line->numElements == 3 &&      if (kwType && line->numElements == 3 &&
1203      !strcmp(line->elements[1].item, kwType->key)) {      !strcmp(line->elements[1].item, kwType->key) &&
1204        !is_special_grub2_variable(line->elements[2].item)) {
1205   dbgPrintf("Line sets default config\n");   dbgPrintf("Line sets default config\n");
1206   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1207   defaultLine = line;   defaultLine = line;
1208      }      }
  } else if (line->type == LT_DEFAULT && line->numElements == 2) {  
     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;  
     defaultLine = line;  
1209    
1210          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1211      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1212       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1213       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1214       */       */
1215      if (entry->multiboot)      if (entry && entry->multiboot)
1216   line->type = LT_HYPER;   line->type = LT_HYPER;
1217    
1218          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 1011  static struct grubConfig * readConfig(co Line 1224  static struct grubConfig * readConfig(co
1224      for (struct singleLine *l = entry->lines; l; l = l->next) {      for (struct singleLine *l = entry->lines; l; l = l->next) {
1225   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1226      break;      break;
1227   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1228      l->type = LT_HYPER;      l->type = LT_HYPER;
1229      break;      break;
1230   }   }
# Line 1025  static struct grubConfig * readConfig(co Line 1238  static struct grubConfig * readConfig(co
1238      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1239      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1240    
1241   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1242      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1243        /* make the title/default a single argument (undoing our parsing) */
1244      len = 0;      len = 0;
1245      for (int i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1246   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
# Line 1133  static struct grubConfig * readConfig(co Line 1347  static struct grubConfig * readConfig(co
1347      }      }
1348   }   }
1349    
1350     if (line->type == LT_DEFAULT && line->numElements == 2) {
1351        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1352        defaultLine = line;
1353     }
1354    
1355   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1356     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1357     probably responsible for putting new images in the wrong     probably responsible for putting new images in the wrong
# Line 1190  static struct grubConfig * readConfig(co Line 1409  static struct grubConfig * readConfig(co
1409          if (defaultLine->numElements > 2 &&          if (defaultLine->numElements > 2 &&
1410      cfi->defaultSupportSaved &&      cfi->defaultSupportSaved &&
1411      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1412      cfg->defaultImage = DEFAULT_SAVED_GRUB2;   cfg->cfi->defaultIsSaved = 1;
1413     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1414     if (cfg->cfi->getEnv) {
1415        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1416        if (defTitle) {
1417     int index = 0;
1418     if (isnumber(defTitle)) {
1419        index = atoi(defTitle);
1420        entry = findEntryByIndex(cfg, index);
1421     } else {
1422        entry = findEntryByTitle(cfg, defTitle, &index);
1423     }
1424     if (entry)
1425        cfg->defaultImage = index;
1426        }
1427     }
1428   } else if (cfi->defaultIsVariable) {   } else if (cfi->defaultIsVariable) {
1429      char *value = defaultLine->elements[2].item;      char *value = defaultLine->elements[2].item;
1430      while (*value && (*value == '"' || *value == '\'' ||      while (*value && (*value == '"' || *value == '\'' ||
# Line 1219  static struct grubConfig * readConfig(co Line 1453  static struct grubConfig * readConfig(co
1453                                  line->elements[1].item)) break;                                  line->elements[1].item)) break;
1454                  } else if (line) {                  } else if (line) {
1455                      if (!strcmp(defaultLine->elements[1].item,                      if (!strcmp(defaultLine->elements[1].item,
1456                                  extractTitle(line))) break;                                  extractTitle(cfg, line))) break;
1457                  }                  }
1458   i++;   i++;
1459   entry = NULL;   entry = NULL;
# Line 1231  static struct grubConfig * readConfig(co Line 1465  static struct grubConfig * readConfig(co
1465          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1466      }      }
1467   }   }
1468        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1469     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1470     if (defTitle) {
1471        int index = 0;
1472        if (isnumber(defTitle)) {
1473     index = atoi(defTitle);
1474     entry = findEntryByIndex(cfg, index);
1475        } else {
1476     entry = findEntryByTitle(cfg, defTitle, &index);
1477        }
1478        if (entry)
1479     cfg->defaultImage = index;
1480     }
1481      } else {      } else {
1482          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1483      }      }
# Line 1248  static void writeDefault(FILE * out, cha Line 1495  static void writeDefault(FILE * out, cha
1495    
1496      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1497   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1498      else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)      else if (cfg->cfi->defaultIsSaved) {
1499   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1500      else if (cfg->defaultImage > -1) {   if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1501        char *title;
1502        entry = findEntryByIndex(cfg, cfg->defaultImage);
1503        line = getLineByType(LT_MENUENTRY, entry->lines);
1504        if (!line)
1505     line = getLineByType(LT_TITLE, entry->lines);
1506        if (line) {
1507     title = extractTitle(cfg, line);
1508     if (title)
1509        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1510        }
1511     }
1512        } else if (cfg->defaultImage > -1) {
1513   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1514      if (cfg->cfi->defaultIsVariable) {      if (cfg->cfi->defaultIsVariable) {
1515          fprintf(out, "%sset default=\"%d\"\n", indent,          fprintf(out, "%sset default=\"%d\"\n", indent,
# Line 1283  static void writeDefault(FILE * out, cha Line 1542  static void writeDefault(FILE * out, cha
1542              else if (line && (line->numElements == 1) &&              else if (line && (line->numElements == 1) &&
1543                       cfg->cfi->titleBracketed) {                       cfg->cfi->titleBracketed) {
1544   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
1545                          extractTitle(line));                          extractTitle(cfg, line));
1546              }              }
1547   }   }
1548      }      }
# Line 1310  static int writeConfig(struct grubConfig Line 1569  static int writeConfig(struct grubConfig
1569    
1570      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1571         directory to the dir of the symlink */         directory to the dir of the symlink */
1572              rc = chdir(dirname(outName));      char *dir = strdupa(outName);
1573        rc = chdir(dirname(dir));
1574      do {      do {
1575   buf = alloca(len + 1);   buf = alloca(len + 1);
1576   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1352  static int writeConfig(struct grubConfig Line 1612  static int writeConfig(struct grubConfig
1612      while (line) {      while (line) {
1613          if (line->type == LT_SET_VARIABLE && defaultKw &&          if (line->type == LT_SET_VARIABLE && defaultKw &&
1614   line->numElements == 3 &&   line->numElements == 3 &&
1615   !strcmp(line->elements[1].item, defaultKw->key)) {   !strcmp(line->elements[1].item, defaultKw->key) &&
1616     !is_special_grub2_variable(line->elements[2].item)) {
1617      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1618      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1619   } else if (line->type == LT_DEFAULT) {   } else if (line->type == LT_DEFAULT) {
# Line 1497  static char *findDiskForRoot() Line 1758  static char *findDiskForRoot()
1758      return NULL;      return NULL;
1759  }  }
1760    
1761  void printEntry(struct singleEntry * entry) {  void printEntry(struct singleEntry * entry, FILE *f) {
1762      int i;      int i;
1763      struct singleLine * line;      struct singleLine * line;
1764    
1765      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
1766   fprintf(stderr, "DBG: %s", line->indent);   log_message(f, "DBG: %s", line->indent);
1767   for (i = 0; i < line->numElements; i++) {   for (i = 0; i < line->numElements; i++) {
1768      /* Need to handle this, because we strip the quotes from      /* Need to handle this, because we strip the quotes from
1769       * menuentry when read it. */       * menuentry when read it. */
1770      if (line->type == LT_MENUENTRY && i == 1) {      if (line->type == LT_MENUENTRY && i == 1) {
1771   if(!isquote(*line->elements[i].item))   if(!isquote(*line->elements[i].item))
1772      fprintf(stderr, "\'%s\'", line->elements[i].item);      log_message(f, "\'%s\'", line->elements[i].item);
1773   else   else
1774      fprintf(stderr, "%s", line->elements[i].item);      log_message(f, "%s", line->elements[i].item);
1775   fprintf(stderr, "%s", line->elements[i].indent);   log_message(f, "%s", line->elements[i].indent);
1776    
1777   continue;   continue;
1778      }      }
1779            
1780      fprintf(stderr, "%s%s",      log_message(f, "%s%s",
1781      line->elements[i].item, line->elements[i].indent);      line->elements[i].item, line->elements[i].indent);
1782   }   }
1783   fprintf(stderr, "\n");   log_message(f, "\n");
1784      }      }
1785  }  }
1786    
1787  void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1788  {  {
1789      va_list argp;      static int once;
1790        va_list argp, argq;
1791    
1792        va_start(argp, fmt);
1793    
1794        va_copy(argq, argp);
1795        if (!once) {
1796     log_time(NULL);
1797     log_message(NULL, "command line: %s\n", saved_command_line);
1798        }
1799        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1800        log_vmessage(NULL, fmt, argq);
1801    
1802        printEntry(entry, NULL);
1803        va_end(argq);
1804    
1805      if (!debug)      if (!debug) {
1806     once = 1;
1807         va_end(argp);
1808   return;   return;
1809        }
1810    
1811      va_start(argp, fmt);      if (okay) {
1812     va_end(argp);
1813     return;
1814        }
1815    
1816        if (!once)
1817     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1818        once = 1;
1819      fprintf(stderr, "DBG: Image entry failed: ");      fprintf(stderr, "DBG: Image entry failed: ");
1820      vfprintf(stderr, fmt, argp);      vfprintf(stderr, fmt, argp);
1821      printEntry(entry);      printEntry(entry, stderr);
1822      va_end(argp);      va_end(argp);
1823  }  }
1824    
# Line 1560  int suitableImage(struct singleEntry * e Line 1845  int suitableImage(struct singleEntry * e
1845      char * rootdev;      char * rootdev;
1846    
1847      if (skipRemoved && entry->skip) {      if (skipRemoved && entry->skip) {
1848   notSuitablePrintf(entry, "marked to skip\n");   notSuitablePrintf(entry, 0, "marked to skip\n");
1849   return 0;   return 0;
1850      }      }
1851    
1852      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1853      if (!line) {      if (!line) {
1854   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1855   return 0;   return 0;
1856      }      }
1857      if (line->numElements < 2) {      if (line->numElements < 2) {
1858   notSuitablePrintf(entry, "line has only %d elements\n",   notSuitablePrintf(entry, 0, "line has only %d elements\n",
1859      line->numElements);      line->numElements);
1860   return 0;   return 0;
1861      }      }
1862    
1863      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1864        notSuitablePrintf(entry, 1, "\n");
1865        return 1;
1866        }
1867    
1868      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1869        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
# Line 1586  int suitableImage(struct singleEntry * e Line 1874  int suitableImage(struct singleEntry * e
1874      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1875              line->elements[1].item + rootspec_offset);              line->elements[1].item + rootspec_offset);
1876      if (access(fullName, R_OK)) {      if (access(fullName, R_OK)) {
1877   notSuitablePrintf(entry, "access to %s failed\n", fullName);   notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1878   return 0;   return 0;
1879      }      }
1880      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 1607  int suitableImage(struct singleEntry * e Line 1895  int suitableImage(struct singleEntry * e
1895    
1896              /* failed to find one */              /* failed to find one */
1897              if (!line) {              if (!line) {
1898   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1899   return 0;   return 0;
1900              }              }
1901    
# Line 1616  int suitableImage(struct singleEntry * e Line 1904  int suitableImage(struct singleEntry * e
1904      if (i < line->numElements)      if (i < line->numElements)
1905          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1906      else {      else {
1907   notSuitablePrintf(entry, "no root= entry found\n");   notSuitablePrintf(entry, 0, "no root= entry found\n");
1908   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1909          return 0;          return 0;
1910              }              }
# Line 1625  int suitableImage(struct singleEntry * e Line 1913  int suitableImage(struct singleEntry * e
1913    
1914      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1915      if (!getpathbyspec(dev)) {      if (!getpathbyspec(dev)) {
1916          notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);          notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1917          return 0;          return 0;
1918      } else      } else
1919   dev = getpathbyspec(dev);   dev = getpathbyspec(dev);
1920    
1921      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1922      if (!rootdev) {      if (!rootdev) {
1923          notSuitablePrintf(entry, "can't find root device\n");          notSuitablePrintf(entry, 0, "can't find root device\n");
1924   return 0;   return 0;
1925      }      }
1926    
1927      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1928          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1929   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1930          free(rootdev);          free(rootdev);
1931          return 0;          return 0;
1932      }      }
1933    
1934      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1935          notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1936   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1937   free(rootdev);   free(rootdev);
1938          return 0;          return 0;
1939      }      }
1940    
1941      free(rootdev);      free(rootdev);
1942        notSuitablePrintf(entry, 1, "\n");
1943    
1944      return 1;      return 1;
1945  }  }
# Line 1684  struct singleEntry * findEntryByPath(str Line 1973  struct singleEntry * findEntryByPath(str
1973   }   }
1974    
1975   indexVars[i + 1] = -1;   indexVars[i + 1] = -1;
1976    
1977   i = 0;   i = 0;
1978   if (index) {   if (index) {
1979      while (i < *index) i++;      while (i < *index) {
1980      if (indexVars[i] == -1) return NULL;   i++;
1981     if (indexVars[i] == -1) return NULL;
1982        }
1983   }   }
1984    
1985   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1986   if (!entry) return NULL;   if (!entry) return NULL;
1987    
1988   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1989   if (!line) return NULL;   if (!line) return NULL;
1990    
1991   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1743  struct singleEntry * findEntryByPath(str Line 2034  struct singleEntry * findEntryByPath(str
2034    
2035      /* check all the lines matching checkType */      /* check all the lines matching checkType */
2036      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2037   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
2038       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
2039       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2040   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
2041        ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2042     line = getLineByType(ct, line);
2043     if (!line)
2044        break;  /* not found in this entry */
2045    
2046   if (line && line->type != LT_MENUENTRY &&   if (line && line->type != LT_MENUENTRY &&
2047   line->numElements >= 2) {   line->numElements >= 2) {
# Line 1765  struct singleEntry * findEntryByPath(str Line 2060  struct singleEntry * findEntryByPath(str
2060       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2061       * unfortunate)       * unfortunate)
2062       */       */
2063      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2064   break; /* found 'im! */   break; /* found 'im! */
2065   }   }
2066    
# Line 1775  struct singleEntry * findEntryByPath(str Line 2070  struct singleEntry * findEntryByPath(str
2070      return entry;      return entry;
2071  }  }
2072    
2073    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2074          int * index) {
2075        struct singleEntry * entry;
2076        struct singleLine * line;
2077        int i;
2078        char * newtitle;
2079    
2080        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2081     if (index && i < *index)
2082        continue;
2083     line = getLineByType(LT_TITLE, entry->lines);
2084     if (!line)
2085        line = getLineByType(LT_MENUENTRY, entry->lines);
2086     if (!line)
2087        continue;
2088     newtitle = grub2ExtractTitle(line);
2089     if (!newtitle)
2090        continue;
2091     if (!strcmp(title, newtitle))
2092        break;
2093        }
2094    
2095        if (!entry)
2096     return NULL;
2097    
2098        if (index)
2099     *index = i;
2100        return entry;
2101    }
2102    
2103  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2104      struct singleEntry * entry;      struct singleEntry * entry;
2105    
# Line 1797  struct singleEntry * findTemplate(struct Line 2122  struct singleEntry * findTemplate(struct
2122      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2123      int index;      int index;
2124    
2125      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2126     if (cfg->cfi->getEnv) {
2127        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2128        if (defTitle) {
2129     int index = 0;
2130     if (isnumber(defTitle)) {
2131        index = atoi(defTitle);
2132        entry = findEntryByIndex(cfg, index);
2133     } else {
2134        entry = findEntryByTitle(cfg, defTitle, &index);
2135     }
2136     if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2137        cfg->defaultImage = index;
2138        if (indexPtr)
2139     *indexPtr = index;
2140        return entry;
2141     }
2142        }
2143     }
2144        } else if (cfg->defaultImage > -1) {
2145   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2146   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2147      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1867  void markRemovedImage(struct grubConfig Line 2211  void markRemovedImage(struct grubConfig
2211    
2212  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2213       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2214       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2215      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2216      int i, j;      int i, j;
2217    
2218      if (newIsDefault) {      if (newIsDefault) {
2219   config->defaultImage = 0;   config->defaultImage = 0;
2220   return;   return;
2221        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2222     if (findEntryByIndex(config, index))
2223        config->defaultImage = index;
2224     else
2225        config->defaultImage = -1;
2226     return;
2227      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2228   i = 0;   i = 0;
2229   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1945  void displayEntry(struct singleEntry * e Line 2295  void displayEntry(struct singleEntry * e
2295      struct singleLine * line;      struct singleLine * line;
2296      char * root = NULL;      char * root = NULL;
2297      int i;      int i;
2298        int j;
2299    
2300      printf("index=%d\n", index);      printf("index=%d\n", index);
2301    
2302      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2303      if (!line) {      if (!line) {
2304          printf("non linux entry\n");          printf("non linux entry\n");
2305          return;          return;
# Line 2013  void displayEntry(struct singleEntry * e Line 2364  void displayEntry(struct singleEntry * e
2364   printf("root=%s\n", s);   printf("root=%s\n", s);
2365      }      }
2366    
2367      line = getLineByType(LT_INITRD, entry->lines);      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2368    
2369      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2370   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
# Line 2032  void displayEntry(struct singleEntry * e Line 2383  void displayEntry(struct singleEntry * e
2383      } else {      } else {
2384   char * title;   char * title;
2385   line = getLineByType(LT_MENUENTRY, entry->lines);   line = getLineByType(LT_MENUENTRY, entry->lines);
2386   title = grub2ExtractTitle(line);   if (line) {
2387   if (title)      title = grub2ExtractTitle(line);
2388      printf("title=%s\n", title);      if (title)
2389     printf("title=%s\n", title);
2390     }
2391        }
2392    
2393        for (j = 0, line = entry->lines; line; line = line->next) {
2394     if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
2395        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2396     printf("mbmodule%d=", j);
2397        else
2398     printf("mbmodule%d=%s", j, prefix);
2399    
2400        for (i = 1; i < line->numElements; i++)
2401     printf("%s%s", line->elements[i].item, line->elements[i].indent);
2402        printf("\n");
2403        j++;
2404     }
2405        }
2406    }
2407    
2408    int isSuseSystem(void) {
2409        const char * path;
2410        const static char default_path[] = "/etc/SuSE-release";
2411    
2412        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2413     path = default_path;
2414    
2415        if (!access(path, R_OK))
2416     return 1;
2417        return 0;
2418    }
2419    
2420    int isSuseGrubConf(const char * path) {
2421        FILE * grubConf;
2422        char * line = NULL;
2423        size_t len = 0, res = 0;
2424    
2425        grubConf = fopen(path, "r");
2426        if (!grubConf) {
2427            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2428     return 0;
2429        }
2430    
2431        while ((res = getline(&line, &len, grubConf)) != -1) {
2432     if (!strncmp(line, "setup", 5)) {
2433        fclose(grubConf);
2434        free(line);
2435        return 1;
2436     }
2437        }
2438    
2439        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2440          path);
2441    
2442        fclose(grubConf);
2443        free(line);
2444        return 0;
2445    }
2446    
2447    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2448        FILE * grubConf;
2449        char * line = NULL;
2450        size_t res = 0, len = 0;
2451    
2452        if (!path) return 1;
2453        if (!lbaPtr) return 1;
2454    
2455        grubConf = fopen(path, "r");
2456        if (!grubConf) return 1;
2457    
2458        while ((res = getline(&line, &len, grubConf)) != -1) {
2459     if (line[res - 1] == '\n')
2460        line[res - 1] = '\0';
2461     else if (len > res)
2462        line[res] = '\0';
2463     else {
2464        line = realloc(line, res + 1);
2465        line[res] = '\0';
2466     }
2467    
2468     if (!strncmp(line, "setup", 5)) {
2469        if (strstr(line, "--force-lba")) {
2470            *lbaPtr = 1;
2471        } else {
2472            *lbaPtr = 0;
2473        }
2474        dbgPrintf("lba: %i\n", *lbaPtr);
2475        break;
2476     }
2477        }
2478    
2479        free(line);
2480        fclose(grubConf);
2481        return 0;
2482    }
2483    
2484    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2485        FILE * grubConf;
2486        char * line = NULL;
2487        size_t res = 0, len = 0;
2488        char * lastParamPtr = NULL;
2489        char * secLastParamPtr = NULL;
2490        char installDeviceNumber = '\0';
2491        char * bounds = NULL;
2492    
2493        if (!path) return 1;
2494        if (!devicePtr) return 1;
2495    
2496        grubConf = fopen(path, "r");
2497        if (!grubConf) return 1;
2498    
2499        while ((res = getline(&line, &len, grubConf)) != -1) {
2500     if (strncmp(line, "setup", 5))
2501        continue;
2502    
2503     if (line[res - 1] == '\n')
2504        line[res - 1] = '\0';
2505     else if (len > res)
2506        line[res] = '\0';
2507     else {
2508        line = realloc(line, res + 1);
2509        line[res] = '\0';
2510     }
2511    
2512     lastParamPtr = bounds = line + res;
2513    
2514     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2515     while (!isspace(*lastParamPtr))
2516        lastParamPtr--;
2517     lastParamPtr++;
2518    
2519     secLastParamPtr = lastParamPtr - 2;
2520     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2521    
2522     if (lastParamPtr + 3 > bounds) {
2523        dbgPrintf("lastParamPtr going over boundary");
2524        fclose(grubConf);
2525        free(line);
2526        return 1;
2527     }
2528     if (!strncmp(lastParamPtr, "(hd", 3))
2529        lastParamPtr += 3;
2530     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2531    
2532     /*
2533     * Second last parameter will decide wether last parameter is
2534     * an IMAGE_DEVICE or INSTALL_DEVICE
2535     */
2536     while (!isspace(*secLastParamPtr))
2537        secLastParamPtr--;
2538     secLastParamPtr++;
2539    
2540     if (secLastParamPtr + 3 > bounds) {
2541        dbgPrintf("secLastParamPtr going over boundary");
2542        fclose(grubConf);
2543        free(line);
2544        return 1;
2545     }
2546     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2547     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2548        secLastParamPtr += 3;
2549        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2550        installDeviceNumber = *secLastParamPtr;
2551     } else {
2552        installDeviceNumber = *lastParamPtr;
2553     }
2554    
2555     *devicePtr = malloc(6);
2556     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2557     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2558     fclose(grubConf);
2559     free(line);
2560     return 0;
2561        }
2562    
2563        free(line);
2564        fclose(grubConf);
2565        return 1;
2566    }
2567    
2568    int grubGetBootFromDeviceMap(const char * device,
2569         char ** bootPtr) {
2570        FILE * deviceMap;
2571        char * line = NULL;
2572        size_t res = 0, len = 0;
2573        char * devicePtr;
2574        char * bounds = NULL;
2575        const char * path;
2576        const static char default_path[] = "/boot/grub/device.map";
2577    
2578        if (!device) return 1;
2579        if (!bootPtr) return 1;
2580    
2581        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2582     path = default_path;
2583    
2584        dbgPrintf("opening grub device.map file from: %s\n", path);
2585        deviceMap = fopen(path, "r");
2586        if (!deviceMap)
2587     return 1;
2588    
2589        while ((res = getline(&line, &len, deviceMap)) != -1) {
2590            if (!strncmp(line, "#", 1))
2591        continue;
2592    
2593     if (line[res - 1] == '\n')
2594        line[res - 1] = '\0';
2595     else if (len > res)
2596        line[res] = '\0';
2597     else {
2598        line = realloc(line, res + 1);
2599        line[res] = '\0';
2600     }
2601    
2602     devicePtr = line;
2603     bounds = line + res;
2604    
2605     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2606        devicePtr++;
2607     dbgPrintf("device: %s\n", devicePtr);
2608    
2609     if (!strncmp(devicePtr, device, strlen(device))) {
2610        devicePtr += strlen(device);
2611        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2612            devicePtr++;
2613    
2614        *bootPtr = strdup(devicePtr);
2615        break;
2616     }
2617        }
2618    
2619        free(line);
2620        fclose(deviceMap);
2621        return 0;
2622    }
2623    
2624    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2625        char * grubDevice;
2626    
2627        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2628     dbgPrintf("error looking for grub installation device\n");
2629        else
2630     dbgPrintf("grubby installation device: %s\n", grubDevice);
2631    
2632        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2633     dbgPrintf("error looking for grub boot device\n");
2634        else
2635     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2636    
2637        free(grubDevice);
2638        return 0;
2639    }
2640    
2641    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2642        /*
2643         * This SuSE grub configuration file at this location is not your average
2644         * grub configuration file, but instead the grub commands used to setup
2645         * grub on that system.
2646         */
2647        const char * path;
2648        const static char default_path[] = "/etc/grub.conf";
2649    
2650        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2651     path = default_path;
2652    
2653        if (!isSuseGrubConf(path)) return 1;
2654    
2655        if (lbaPtr) {
2656            *lbaPtr = 0;
2657            if (suseGrubConfGetLba(path, lbaPtr))
2658                return 1;
2659        }
2660    
2661        if (bootPtr) {
2662            *bootPtr = NULL;
2663            suseGrubConfGetBoot(path, bootPtr);
2664      }      }
2665    
2666        return 0;
2667  }  }
2668    
2669  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 2086  int parseSysconfigGrub(int * lbaPtr, cha Line 2714  int parseSysconfigGrub(int * lbaPtr, cha
2714  }  }
2715    
2716  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2717      char * boot;      char * boot = NULL;
2718      int lba;      int lba;
2719    
2720      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2721   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2722   if (boot) printf("boot=%s\n", boot);      free(boot);
2723        return;
2724     }
2725        } else {
2726            if (parseSysconfigGrub(&lba, &boot)) {
2727        free(boot);
2728        return;
2729     }
2730        }
2731    
2732        if (lba) printf("lba\n");
2733        if (boot) {
2734     printf("boot=%s\n", boot);
2735     free(boot);
2736      }      }
2737  }  }
2738    
# Line 2140  struct singleLine * addLineTmpl(struct s Line 2781  struct singleLine * addLineTmpl(struct s
2781  {  {
2782      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2783    
2784        if (isEfi && cfi == &grub2ConfigType) {
2785     enum lineType_e old = newLine->type;
2786     newLine->type = preferredLineType(newLine->type, cfi);
2787     if (old != newLine->type)
2788        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2789        }
2790    
2791      if (val) {      if (val) {
2792   /* override the inherited value with our own.   /* override the inherited value with our own.
2793   * 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 2149  struct singleLine * addLineTmpl(struct s Line 2797  struct singleLine * addLineTmpl(struct s
2797   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2798    
2799   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2800   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)) {
2801      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2802      if (rootspec != NULL) {      if (rootspec != NULL) {
2803   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 2186  struct singleLine *  addLine(struct sing Line 2834  struct singleLine *  addLine(struct sing
2834      /* 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
2835       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2836       */       */
   
2837      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2838   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2839   tmpl.type = type;   tmpl.type = type;
# Line 2520  int updateActualImage(struct grubConfig Line 3167  int updateActualImage(struct grubConfig
3167      firstElement = 2;      firstElement = 2;
3168    
3169   } else {   } else {
3170      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3171      if (!line) {      if (!line) {
3172   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3173   continue;   continue;
# Line 2676  int updateImage(struct grubConfig * cfg, Line 3323  int updateImage(struct grubConfig * cfg,
3323      return rc;      return rc;
3324  }  }
3325    
3326    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3327     const char * image, const char * prefix, const char * initrd,
3328     const char * title) {
3329        struct singleEntry * entry;
3330        struct singleLine * line, * kernelLine, *endLine = NULL;
3331        int index = 0;
3332    
3333        if (!image) return 0;
3334    
3335        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3336            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3337            if (!kernelLine) continue;
3338    
3339     /* if title is supplied, the entry's title must match it. */
3340     if (title) {
3341        char *linetitle;
3342    
3343        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3344        if (!line)
3345     continue;
3346    
3347        linetitle = extractTitle(cfg, line);
3348        if (!linetitle)
3349     continue;
3350        if (strcmp(title, linetitle)) {
3351     free(linetitle);
3352     continue;
3353        }
3354        free(linetitle);
3355     }
3356    
3357            if (prefix) {
3358                int prefixLen = strlen(prefix);
3359                if (!strncmp(initrd, prefix, prefixLen))
3360                    initrd += prefixLen;
3361            }
3362     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3363     if (endLine)
3364        removeLine(entry, endLine);
3365            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3366     kernelLine->indent, initrd);
3367            if (!line)
3368        return 1;
3369     if (endLine) {
3370        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3371                if (!line)
3372     return 1;
3373     }
3374    
3375            break;
3376        }
3377    
3378        return 0;
3379    }
3380    
3381  int updateInitrd(struct grubConfig * cfg, const char * image,  int updateInitrd(struct grubConfig * cfg, const char * image,
3382                   const char * prefix, const char * initrd) {                   const char * prefix, const char * initrd, const char * title) {
3383      struct singleEntry * entry;      struct singleEntry * entry;
3384      struct singleLine * line, * kernelLine, *endLine = NULL;      struct singleLine * line, * kernelLine, *endLine = NULL;
3385      int index = 0;      int index = 0;
# Line 2685  int updateInitrd(struct grubConfig * cfg Line 3387  int updateInitrd(struct grubConfig * cfg
3387      if (!image) return 0;      if (!image) return 0;
3388    
3389      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3390          kernelLine = getLineByType(LT_KERNEL, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3391          if (!kernelLine) continue;          if (!kernelLine) continue;
3392    
3393          line = getLineByType(LT_INITRD, entry->lines);   /* if title is supplied, the entry's title must match it. */
3394     if (title) {
3395        char *linetitle;
3396    
3397        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3398        if (!line)
3399     continue;
3400    
3401        linetitle = extractTitle(cfg, line);
3402        if (!linetitle)
3403     continue;
3404        if (strcmp(title, linetitle)) {
3405     free(linetitle);
3406     continue;
3407        }
3408        free(linetitle);
3409     }
3410    
3411            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3412          if (line)          if (line)
3413              removeLine(entry, line);              removeLine(entry, line);
3414          if (prefix) {          if (prefix) {
# Line 2699  int updateInitrd(struct grubConfig * cfg Line 3419  int updateInitrd(struct grubConfig * cfg
3419   endLine = getLineByType(LT_ENTRY_END, entry->lines);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3420   if (endLine)   if (endLine)
3421      removeLine(entry, endLine);      removeLine(entry, endLine);
3422          line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);   enum lineType_e lt;
3423     switch(kernelLine->type) {
3424        case LT_KERNEL:
3425            lt = LT_INITRD;
3426     break;
3427        case LT_KERNEL_EFI:
3428            lt = LT_INITRD_EFI;
3429     break;
3430        case LT_KERNEL_16:
3431            lt = LT_INITRD_16;
3432     break;
3433        default:
3434            lt = preferredLineType(LT_INITRD, cfg->cfi);
3435     }
3436            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3437          if (!line)          if (!line)
3438      return 1;      return 1;
3439   if (endLine) {   if (endLine) {
# Line 2905  int checkForGrub(struct grubConfig * con Line 3639  int checkForGrub(struct grubConfig * con
3639      int fd;      int fd;
3640      unsigned char bootSect[512];      unsigned char bootSect[512];
3641      char * boot;      char * boot;
3642        int onSuse = isSuseSystem();
3643    
3644      if (parseSysconfigGrub(NULL, &boot))  
3645   return 0;      if (onSuse) {
3646     if (parseSuseGrubConf(NULL, &boot))
3647        return 0;
3648        } else {
3649     if (parseSysconfigGrub(NULL, &boot))
3650        return 0;
3651        }
3652    
3653      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3654      if (!boot)      if (!boot)
# Line 2926  int checkForGrub(struct grubConfig * con Line 3667  int checkForGrub(struct grubConfig * con
3667      }      }
3668      close(fd);      close(fd);
3669    
3670        /* The more elaborate checks do not work on SuSE. The checks done
3671         * seem to be reasonble (at least for now), so just return success
3672         */
3673        if (onSuse)
3674     return 2;
3675    
3676      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3677  }  }
3678    
# Line 2959  int checkForExtLinux(struct grubConfig * Line 3706  int checkForExtLinux(struct grubConfig *
3706      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3707  }  }
3708    
3709    int checkForYaboot(struct grubConfig * config) {
3710        /*
3711         * This is a simplistic check that we consider good enough for own puporses
3712         *
3713         * If we were to properly check if yaboot is *installed* we'd need to:
3714         * 1) get the system boot device (LT_BOOT)
3715         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3716         *    the content on the boot device
3717         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3718         * 4) check again if binary and boot device contents match
3719         */
3720        if (!access("/etc/yaboot.conf", R_OK))
3721     return 2;
3722    
3723        return 1;
3724    }
3725    
3726    int checkForElilo(struct grubConfig * config) {
3727        if (!access("/etc/elilo.conf", R_OK))
3728     return 2;
3729    
3730        return 1;
3731    }
3732    
3733  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3734      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3735    
# Line 3021  int addNewKernel(struct grubConfig * con Line 3792  int addNewKernel(struct grubConfig * con
3792   const char * newKernelPath, const char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3793   const char * newKernelArgs, const char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3794   const char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3795                   const char * newMBKernel, const char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3796     const char * newDevTreePath) {
3797      struct singleEntry * new;      struct singleEntry * new;
3798      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3799      int needs;      int needs;
# Line 3062  int addNewKernel(struct grubConfig * con Line 3834  int addNewKernel(struct grubConfig * con
3834          needs |= NEED_MB;          needs |= NEED_MB;
3835          new->multiboot = 1;          new->multiboot = 1;
3836      }      }
3837        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3838     needs |= NEED_DEVTREE;
3839    
3840      if (template) {      if (template) {
3841   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 3075  int addNewKernel(struct grubConfig * con Line 3849  int addNewKernel(struct grubConfig * con
3849      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3850      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3851    
3852      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
     tmplLine->numElements >= 2) {  
3853   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3854      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3855       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 3153  int addNewKernel(struct grubConfig * con Line 3926  int addNewKernel(struct grubConfig * con
3926      /* template is multi but new is not,      /* template is multi but new is not,
3927       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3928       */       */
3929      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3930      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3931      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3932   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3933     config->cfi)->key);
3934      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3935    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3936      config->cfi);
3937      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3938   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3939      char *initrdVal;      char *initrdVal;
3940      /* template is multi but new is not,      /* template is multi but new is not,
3941       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3942       */       */
3943      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3944      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3945      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3946   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3947     config->cfi)->key);
3948      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3949      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3950      free(initrdVal);      free(initrdVal);
3951      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3952   }   }
3953    
3954      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3955   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3956      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3957      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 3230  int addNewKernel(struct grubConfig * con Line 4005  int addNewKernel(struct grubConfig * con
4005      static const char *prefix = "'Loading ";      static const char *prefix = "'Loading ";
4006      if (tmplLine->numElements > 1 &&      if (tmplLine->numElements > 1 &&
4007      strstr(tmplLine->elements[1].item, prefix) &&      strstr(tmplLine->elements[1].item, prefix) &&
4008      masterLine->next && masterLine->next->type == LT_KERNEL) {      masterLine->next &&
4009        iskernel(masterLine->next->type)) {
4010   char *newTitle = malloc(strlen(prefix) +   char *newTitle = malloc(strlen(prefix) +
4011   strlen(newKernelTitle) + 2);   strlen(newKernelTitle) + 2);
4012    
# Line 3245  int addNewKernel(struct grubConfig * con Line 4021  int addNewKernel(struct grubConfig * con
4021   newLine = addLineTmpl(new, tmplLine, newLine, NULL,   newLine = addLineTmpl(new, tmplLine, newLine, NULL,
4022   config->cfi);   config->cfi);
4023      }      }
4024        } else if (tmplLine->type == LT_DEVTREE &&
4025           tmplLine->numElements == 2 && newDevTreePath) {
4026            newLine = addLineTmpl(new, tmplLine, newLine,
4027          newDevTreePath + strlen(prefix),
4028          config->cfi);
4029     needs &= ~NEED_DEVTREE;
4030        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
4031     const char *ndtp = newDevTreePath;
4032     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
4033        ndtp += strlen(prefix);
4034     newLine = addLine(new, config->cfi, LT_DEVTREE,
4035      config->secondaryIndent,
4036      ndtp);
4037     needs &= ~NEED_DEVTREE;
4038     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4039      } else {      } else {
4040   /* pass through other lines from the template */   /* pass through other lines from the template */
4041   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 3257  int addNewKernel(struct grubConfig * con Line 4048  int addNewKernel(struct grubConfig * con
4048   */   */
4049   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
4050      case LT_KERNEL:      case LT_KERNEL:
4051        case LT_KERNEL_EFI:
4052        case LT_KERNEL_16:
4053   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
4054      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
4055   } else {   } else {
4056      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
4057              preferredLineType(LT_KERNEL, config->cfi),
4058        config->primaryIndent,        config->primaryIndent,
4059        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
4060      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 3317  int addNewKernel(struct grubConfig * con Line 4111  int addNewKernel(struct grubConfig * con
4111   }   }
4112      }      }
4113    
4114        struct singleLine *endLine = NULL;
4115        endLine = getLineByType(LT_ENTRY_END, new->lines);
4116        if (endLine) {
4117        removeLine(new, endLine);
4118        needs |= NEED_END;
4119        }
4120    
4121      /* add the remainder of the lines, i.e. those that either      /* add the remainder of the lines, i.e. those that either
4122       * 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,
4123       * all the lines following the entryStart.       * all the lines following the entryStart.
# Line 3336  int addNewKernel(struct grubConfig * con Line 4137  int addNewKernel(struct grubConfig * con
4137      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
4138   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4139    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4140        config->cfi)) ?        config->cfi))
4141    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
4142     : preferredLineType(LT_KERNEL, config->cfi),
4143    config->secondaryIndent,    config->secondaryIndent,
4144    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
4145   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 3353  int addNewKernel(struct grubConfig * con Line 4155  int addNewKernel(struct grubConfig * con
4155   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4156   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4157    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4158        config->cfi)) ?        config->cfi))
4159    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
4160       : preferredLineType(LT_INITRD, config->cfi),
4161    config->secondaryIndent,    config->secondaryIndent,
4162    initrdVal);    initrdVal);
4163   free(initrdVal);   free(initrdVal);
4164   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4165      }      }
4166        if (needs & NEED_DEVTREE) {
4167     newLine = addLine(new, config->cfi, LT_DEVTREE,
4168      config->secondaryIndent,
4169      newDevTreePath);
4170     needs &= ~NEED_DEVTREE;
4171        }
4172    
4173        /* NEEDS_END must be last on bootloaders that need it... */
4174      if (needs & NEED_END) {      if (needs & NEED_END) {
4175   newLine = addLine(new, config->cfi, LT_ENTRY_END,   newLine = addLine(new, config->cfi, LT_ENTRY_END,
4176   config->secondaryIndent, NULL);   config->secondaryIndent, NULL);
# Line 3386  static void traceback(int signum) Line 4197  static void traceback(int signum)
4197      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
4198      size = backtrace(array, 40);      size = backtrace(array, 40);
4199    
4200      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4201              (unsigned long)size);              (unsigned long)size);
4202      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
4203      exit(1);      exit(1);
# Line 3411  int main(int argc, const char ** argv) { Line 4222  int main(int argc, const char ** argv) {
4222      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4223      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4224      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4225      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4226      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4227      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4228      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 3421  int main(int argc, const char ** argv) { Line 4232  int main(int argc, const char ** argv) {
4232      char * removeArgs = NULL;      char * removeArgs = NULL;
4233      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4234      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4235        char * envPath = NULL;
4236      const char * chptr = NULL;      const char * chptr = NULL;
4237      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4238      struct grubConfig * config;      struct grubConfig * config;
# Line 3429  int main(int argc, const char ** argv) { Line 4241  int main(int argc, const char ** argv) {
4241      int displayDefault = 0;      int displayDefault = 0;
4242      int displayDefaultIndex = 0;      int displayDefaultIndex = 0;
4243      int displayDefaultTitle = 0;      int displayDefaultTitle = 0;
4244        int defaultIndex = -1;
4245      struct poptOption options[] = {      struct poptOption options[] = {
4246   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4247      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 3446  int main(int argc, const char ** argv) { Line 4259  int main(int argc, const char ** argv) {
4259   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4260      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4261      _("bootfs") },      _("bootfs") },
4262  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4263   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4264      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4265  #endif  #endif
4266   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4267      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 3467  int main(int argc, const char ** argv) { Line 4280  int main(int argc, const char ** argv) {
4280      _("display the index of the default kernel") },      _("display the index of the default kernel") },
4281   { "default-title", 0, 0, &displayDefaultTitle, 0,   { "default-title", 0, 0, &displayDefaultTitle, 0,
4282      _("display the title of the default kernel") },      _("display the title of the default kernel") },
4283     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4284        _("device tree file for new stanza"), _("dtb-path") },
4285     { "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4286        _("device tree directory for new stanza"), _("dtb-path") },
4287   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4288      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4289     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4290        _("force grub2 stanzas to use efi") },
4291     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4292        _("path for environment data"),
4293        _("path") },
4294   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4295      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4296   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
# Line 3481  int main(int argc, const char ** argv) { Line 4303  int main(int argc, const char ** argv) {
4303   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4304      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4305   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4306      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4307   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4308      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4309   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 3501  int main(int argc, const char ** argv) { Line 4323  int main(int argc, const char ** argv) {
4323   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4324      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4325        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4326     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4327        _("make the given entry index the default entry"),
4328        _("entry-index") },
4329   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4330      _("configure silo bootloader") },      _("configure silo bootloader") },
4331   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 3522  int main(int argc, const char ** argv) { Line 4347  int main(int argc, const char ** argv) {
4347    
4348      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4349    
4350        int i = 0;
4351        for (int j = 1; j < argc; j++)
4352     i += strlen(argv[j]) + 1;
4353        saved_command_line = malloc(i);
4354        if (!saved_command_line) {
4355     fprintf(stderr, "grubby: %m\n");
4356     exit(1);
4357        }
4358        saved_command_line[0] = '\0';
4359        for (int j = 1; j < argc; j++) {
4360     strcat(saved_command_line, argv[j]);
4361     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4362        }
4363    
4364      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4365      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4366    
# Line 3565  int main(int argc, const char ** argv) { Line 4404  int main(int argc, const char ** argv) {
4404   return 1;   return 1;
4405      } else if (configureGrub2) {      } else if (configureGrub2) {
4406   cfi = &grub2ConfigType;   cfi = &grub2ConfigType;
4407     if (envPath)
4408        cfi->envFile = envPath;
4409      } else if (configureLilo) {      } else if (configureLilo) {
4410   cfi = &liloConfigType;   cfi = &liloConfigType;
4411      } else if (configureGrub) {      } else if (configureGrub) {
# Line 3583  int main(int argc, const char ** argv) { Line 4424  int main(int argc, const char ** argv) {
4424      }      }
4425    
4426      if (!cfi) {      if (!cfi) {
4427          if (grub2FindConfig(&grub2ConfigType))          if (grub2FindConfig(&grub2ConfigType)) {
4428      cfi = &grub2ConfigType;      cfi = &grub2ConfigType;
4429   else      if (envPath)
4430     cfi->envFile = envPath;
4431            } else
4432        #ifdef __ia64__        #ifdef __ia64__
4433      cfi = &eliloConfigType;      cfi = &eliloConfigType;
4434        #elif __powerpc__        #elif __powerpc__
# Line 3608  int main(int argc, const char ** argv) { Line 4451  int main(int argc, const char ** argv) {
4451      grubConfig = cfi->defaultConfig;      grubConfig = cfi->defaultConfig;
4452      }      }
4453    
4454      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4455    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4456    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {      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 3626  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 3652  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 (grubConfig && !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 "
# Line 3660  int main(int argc, const char ** argv) { Line 4509  int main(int argc, const char ** argv) {
4509      }      }
4510    
4511      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4512   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4513          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {   && !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 3688  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, gr2c = 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);   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4545   if (grub2config) {   if (grub2config) {
# Line 3717  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 || gr2c == 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");   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 3744  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 3762  int main(int argc, const char ** argv) { Line 4643  int main(int argc, const char ** argv) {
4643   struct singleEntry * entry;   struct singleEntry * entry;
4644    
4645   if (config->defaultImage == -1) return 0;   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);   entry = findEntryByIndex(config, config->defaultImage);
4650   if (!entry) return 0;   if (!entry) return 0;
4651    
# Line 3784  int main(int argc, const char ** argv) { Line 4668  int main(int argc, const char ** argv) {
4668    
4669      } else if (displayDefaultIndex) {      } else if (displayDefaultIndex) {
4670          if (config->defaultImage == -1) return 0;          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);          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);
# Line 3797  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                       (const char **)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) {

Legend:
Removed from v.1849  
changed lines
  Added in v.2986