Magellan Linux

Diff of /trunk/grubby/grubby.c

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

revision 1846 by niro, Mon Jul 2 13:00:11 2012 UTC revision 2980 by niro, Thu Jun 30 10:26:25 2016 UTC
# Line 36  Line 36 
36  #include <signal.h>  #include <signal.h>
37  #include <blkid/blkid.h>  #include <blkid/blkid.h>
38    
39    #include "log.h"
40    
41  #ifndef DEBUG  #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 (cfg->cfi == &grub2ConfigType)
841      title++;   return grub2ExtractTitle(line);
842      *(title + strlen(title) - 1) = '\0';      if (line->type == LT_TITLE) {
843     char *tmp = line->elements[cfg->cfi->titlePosition].item;
844     if (cfg->cfi->titleBracketed) {
845        tmp++;
846        title = strdup(tmp);
847        *(title + strlen(title) - 1) = '\0';
848     } else {
849        title = strdup(tmp);
850     }
851        } else if (line->type == LT_MENUENTRY)
852     title = strdup(line->elements[1].item);
853        else
854     return NULL;
855      return title;      return title;
856  }  }
857    
# Line 904  static int getNextLine(char ** bufPtr, s Line 1109  static int getNextLine(char ** bufPtr, s
1109      return 0;      return 0;
1110  }  }
1111    
1112    static int isnumber(const char *s)
1113    {
1114        int i;
1115        for (i = 0; s[i] != '\0'; i++)
1116     if (s[i] < '0' || s[i] > '9')
1117        return 0;
1118        return i;
1119    }
1120    
1121  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1122        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1123      int in;      int in;
# Line 918  static struct grubConfig * readConfig(co Line 1132  static struct grubConfig * readConfig(co
1132      int len;      int len;
1133      char * buf;      char * buf;
1134    
1135      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1136            printf("Could not find bootloader configuration\n");
1137            exit(1);
1138        } else if (!strcmp(inName, "-")) {
1139   in = 0;   in = 0;
1140      } else {      } else {
1141   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 985  static struct grubConfig * readConfig(co Line 1202  static struct grubConfig * readConfig(co
1202      dbgPrintf("\n");      dbgPrintf("\n");
1203      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1204      if (kwType && line->numElements == 3 &&      if (kwType && line->numElements == 3 &&
1205      !strcmp(line->elements[1].item, kwType->key)) {      !strcmp(line->elements[1].item, kwType->key) &&
1206        !is_special_grub2_variable(line->elements[2].item)) {
1207   dbgPrintf("Line sets default config\n");   dbgPrintf("Line sets default config\n");
1208   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1209   defaultLine = line;   defaultLine = line;
1210      }      }
  } else if (line->type == LT_DEFAULT && line->numElements == 2) {  
     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;  
     defaultLine = line;  
1211    
1212          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1213      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1214       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1215       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1216       */       */
1217      if (entry->multiboot)      if (entry && entry->multiboot)
1218   line->type = LT_HYPER;   line->type = LT_HYPER;
1219    
1220          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 1011  static struct grubConfig * readConfig(co Line 1226  static struct grubConfig * readConfig(co
1226      for (struct singleLine *l = entry->lines; l; l = l->next) {      for (struct singleLine *l = entry->lines; l; l = l->next) {
1227   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1228      break;      break;
1229   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1230      l->type = LT_HYPER;      l->type = LT_HYPER;
1231      break;      break;
1232   }   }
# Line 1025  static struct grubConfig * readConfig(co Line 1240  static struct grubConfig * readConfig(co
1240      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1241      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1242    
1243   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1244      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1245        /* make the title/default a single argument (undoing our parsing) */
1246      len = 0;      len = 0;
1247      for (int i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1248   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
# Line 1133  static struct grubConfig * readConfig(co Line 1349  static struct grubConfig * readConfig(co
1349      }      }
1350   }   }
1351    
1352     if (line->type == LT_DEFAULT && line->numElements == 2) {
1353        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1354        defaultLine = line;
1355     }
1356    
1357   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1358     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1359     probably responsible for putting new images in the wrong     probably responsible for putting new images in the wrong
# Line 1190  static struct grubConfig * readConfig(co Line 1411  static struct grubConfig * readConfig(co
1411          if (defaultLine->numElements > 2 &&          if (defaultLine->numElements > 2 &&
1412      cfi->defaultSupportSaved &&      cfi->defaultSupportSaved &&
1413      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1414      cfg->defaultImage = DEFAULT_SAVED_GRUB2;   cfg->cfi->defaultIsSaved = 1;
1415     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1416     if (cfg->cfi->getEnv) {
1417        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1418        if (defTitle) {
1419     int index = 0;
1420     if (isnumber(defTitle)) {
1421        index = atoi(defTitle);
1422        entry = findEntryByIndex(cfg, index);
1423     } else {
1424        entry = findEntryByTitle(cfg, defTitle, &index);
1425     }
1426     if (entry)
1427        cfg->defaultImage = index;
1428        }
1429     }
1430   } else if (cfi->defaultIsVariable) {   } else if (cfi->defaultIsVariable) {
1431      char *value = defaultLine->elements[2].item;      char *value = defaultLine->elements[2].item;
1432      while (*value && (*value == '"' || *value == '\'' ||      while (*value && (*value == '"' || *value == '\'' ||
# Line 1219  static struct grubConfig * readConfig(co Line 1455  static struct grubConfig * readConfig(co
1455                                  line->elements[1].item)) break;                                  line->elements[1].item)) break;
1456                  } else if (line) {                  } else if (line) {
1457                      if (!strcmp(defaultLine->elements[1].item,                      if (!strcmp(defaultLine->elements[1].item,
1458                                  extractTitle(line))) break;                                  extractTitle(cfg, line))) break;
1459                  }                  }
1460   i++;   i++;
1461   entry = NULL;   entry = NULL;
# Line 1231  static struct grubConfig * readConfig(co Line 1467  static struct grubConfig * readConfig(co
1467          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1468      }      }
1469   }   }
1470        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1471     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1472     if (defTitle) {
1473        int index = 0;
1474        if (isnumber(defTitle)) {
1475     index = atoi(defTitle);
1476     entry = findEntryByIndex(cfg, index);
1477        } else {
1478     entry = findEntryByTitle(cfg, defTitle, &index);
1479        }
1480        if (entry)
1481     cfg->defaultImage = index;
1482     }
1483      } else {      } else {
1484          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1485      }      }
# Line 1248  static void writeDefault(FILE * out, cha Line 1497  static void writeDefault(FILE * out, cha
1497    
1498      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1499   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1500      else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)      else if (cfg->cfi->defaultIsSaved) {
1501   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1502      else if (cfg->defaultImage > -1) {   if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1503        char *title;
1504        entry = findEntryByIndex(cfg, cfg->defaultImage);
1505        line = getLineByType(LT_MENUENTRY, entry->lines);
1506        if (!line)
1507     line = getLineByType(LT_TITLE, entry->lines);
1508        if (line) {
1509     title = extractTitle(cfg, line);
1510     if (title)
1511        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1512        }
1513     }
1514        } else if (cfg->defaultImage > -1) {
1515   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1516      if (cfg->cfi->defaultIsVariable) {      if (cfg->cfi->defaultIsVariable) {
1517          fprintf(out, "%sset default=\"%d\"\n", indent,          fprintf(out, "%sset default=\"%d\"\n", indent,
# Line 1283  static void writeDefault(FILE * out, cha Line 1544  static void writeDefault(FILE * out, cha
1544              else if (line && (line->numElements == 1) &&              else if (line && (line->numElements == 1) &&
1545                       cfg->cfi->titleBracketed) {                       cfg->cfi->titleBracketed) {
1546   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
1547                          extractTitle(line));                          extractTitle(cfg, line));
1548              }              }
1549   }   }
1550      }      }
# Line 1310  static int writeConfig(struct grubConfig Line 1571  static int writeConfig(struct grubConfig
1571    
1572      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1573         directory to the dir of the symlink */         directory to the dir of the symlink */
1574              rc = chdir(dirname(outName));      char *dir = strdupa(outName);
1575        rc = chdir(dirname(dir));
1576      do {      do {
1577   buf = alloca(len + 1);   buf = alloca(len + 1);
1578   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1352  static int writeConfig(struct grubConfig Line 1614  static int writeConfig(struct grubConfig
1614      while (line) {      while (line) {
1615          if (line->type == LT_SET_VARIABLE && defaultKw &&          if (line->type == LT_SET_VARIABLE && defaultKw &&
1616   line->numElements == 3 &&   line->numElements == 3 &&
1617   !strcmp(line->elements[1].item, defaultKw->key)) {   !strcmp(line->elements[1].item, defaultKw->key) &&
1618     !is_special_grub2_variable(line->elements[2].item)) {
1619      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1620      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1621   } else if (line->type == LT_DEFAULT) {   } else if (line->type == LT_DEFAULT) {
# Line 1497  static char *findDiskForRoot() Line 1760  static char *findDiskForRoot()
1760      return NULL;      return NULL;
1761  }  }
1762    
1763  void printEntry(struct singleEntry * entry) {  void printEntry(struct singleEntry * entry, FILE *f) {
1764      int i;      int i;
1765      struct singleLine * line;      struct singleLine * line;
1766    
1767      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
1768   fprintf(stderr, "DBG: %s", line->indent);   log_message(f, "DBG: %s", line->indent);
1769   for (i = 0; i < line->numElements; i++) {   for (i = 0; i < line->numElements; i++) {
1770      /* Need to handle this, because we strip the quotes from      /* Need to handle this, because we strip the quotes from
1771       * menuentry when read it. */       * menuentry when read it. */
1772      if (line->type == LT_MENUENTRY && i == 1) {      if (line->type == LT_MENUENTRY && i == 1) {
1773   if(!isquote(*line->elements[i].item))   if(!isquote(*line->elements[i].item))
1774      fprintf(stderr, "\'%s\'", line->elements[i].item);      log_message(f, "\'%s\'", line->elements[i].item);
1775   else   else
1776      fprintf(stderr, "%s", line->elements[i].item);      log_message(f, "%s", line->elements[i].item);
1777   fprintf(stderr, "%s", line->elements[i].indent);   log_message(f, "%s", line->elements[i].indent);
1778    
1779   continue;   continue;
1780      }      }
1781            
1782      fprintf(stderr, "%s%s",      log_message(f, "%s%s",
1783      line->elements[i].item, line->elements[i].indent);      line->elements[i].item, line->elements[i].indent);
1784   }   }
1785   fprintf(stderr, "\n");   log_message(f, "\n");
1786      }      }
1787  }  }
1788    
1789  void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1790  {  {
1791      va_list argp;      static int once;
1792        va_list argp, argq;
1793    
1794      if (!debug)      va_start(argp, fmt);
1795    
1796        va_copy(argq, argp);
1797        if (!once) {
1798     log_time(NULL);
1799     log_message(NULL, "command line: %s\n", saved_command_line);
1800        }
1801        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1802        log_vmessage(NULL, fmt, argq);
1803    
1804        printEntry(entry, NULL);
1805        va_end(argq);
1806    
1807        if (!debug) {
1808     once = 1;
1809         va_end(argp);
1810   return;   return;
1811        }
1812    
1813      va_start(argp, fmt);      if (okay) {
1814     va_end(argp);
1815     return;
1816        }
1817    
1818        if (!once)
1819     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1820        once = 1;
1821      fprintf(stderr, "DBG: Image entry failed: ");      fprintf(stderr, "DBG: Image entry failed: ");
1822      vfprintf(stderr, fmt, argp);      vfprintf(stderr, fmt, argp);
1823      printEntry(entry);      printEntry(entry, stderr);
1824      va_end(argp);      va_end(argp);
1825  }  }
1826    
# Line 1560  int suitableImage(struct singleEntry * e Line 1847  int suitableImage(struct singleEntry * e
1847      char * rootdev;      char * rootdev;
1848    
1849      if (skipRemoved && entry->skip) {      if (skipRemoved && entry->skip) {
1850   notSuitablePrintf(entry, "marked to skip\n");   notSuitablePrintf(entry, 0, "marked to skip\n");
1851   return 0;   return 0;
1852      }      }
1853    
1854      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1855      if (!line) {      if (!line) {
1856   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1857   return 0;   return 0;
1858      }      }
1859      if (line->numElements < 2) {      if (line->numElements < 2) {
1860   notSuitablePrintf(entry, "line has only %d elements\n",   notSuitablePrintf(entry, 0, "line has only %d elements\n",
1861      line->numElements);      line->numElements);
1862   return 0;   return 0;
1863      }      }
1864    
1865      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1866        notSuitablePrintf(entry, 1, "\n");
1867        return 1;
1868        }
1869    
1870      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1871        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
# Line 1586  int suitableImage(struct singleEntry * e Line 1876  int suitableImage(struct singleEntry * e
1876      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1877              line->elements[1].item + rootspec_offset);              line->elements[1].item + rootspec_offset);
1878      if (access(fullName, R_OK)) {      if (access(fullName, R_OK)) {
1879   notSuitablePrintf(entry, "access to %s failed\n", fullName);   notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1880   return 0;   return 0;
1881      }      }
1882      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 1607  int suitableImage(struct singleEntry * e Line 1897  int suitableImage(struct singleEntry * e
1897    
1898              /* failed to find one */              /* failed to find one */
1899              if (!line) {              if (!line) {
1900   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1901   return 0;   return 0;
1902              }              }
1903    
# Line 1616  int suitableImage(struct singleEntry * e Line 1906  int suitableImage(struct singleEntry * e
1906      if (i < line->numElements)      if (i < line->numElements)
1907          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1908      else {      else {
1909   notSuitablePrintf(entry, "no root= entry found\n");   notSuitablePrintf(entry, 0, "no root= entry found\n");
1910   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1911          return 0;          return 0;
1912              }              }
# Line 1625  int suitableImage(struct singleEntry * e Line 1915  int suitableImage(struct singleEntry * e
1915    
1916      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1917      if (!getpathbyspec(dev)) {      if (!getpathbyspec(dev)) {
1918          notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);          notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1919          return 0;          return 0;
1920      } else      } else
1921   dev = getpathbyspec(dev);   dev = getpathbyspec(dev);
1922    
1923      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1924      if (!rootdev) {      if (!rootdev) {
1925          notSuitablePrintf(entry, "can't find root device\n");          notSuitablePrintf(entry, 0, "can't find root device\n");
1926   return 0;   return 0;
1927      }      }
1928    
1929      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1930          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1931   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1932          free(rootdev);          free(rootdev);
1933          return 0;          return 0;
1934      }      }
1935    
1936      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1937          notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1938   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1939   free(rootdev);   free(rootdev);
1940          return 0;          return 0;
1941      }      }
1942    
1943      free(rootdev);      free(rootdev);
1944        notSuitablePrintf(entry, 1, "\n");
1945    
1946      return 1;      return 1;
1947  }  }
# Line 1684  struct singleEntry * findEntryByPath(str Line 1975  struct singleEntry * findEntryByPath(str
1975   }   }
1976    
1977   indexVars[i + 1] = -1;   indexVars[i + 1] = -1;
1978    
1979   i = 0;   i = 0;
1980   if (index) {   if (index) {
1981      while (i < *index) i++;      while (i < *index) {
1982      if (indexVars[i] == -1) return NULL;   i++;
1983     if (indexVars[i] == -1) return NULL;
1984        }
1985   }   }
1986    
1987   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1988   if (!entry) return NULL;   if (!entry) return NULL;
1989    
1990   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1991   if (!line) return NULL;   if (!line) return NULL;
1992    
1993   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1743  struct singleEntry * findEntryByPath(str Line 2036  struct singleEntry * findEntryByPath(str
2036    
2037      /* check all the lines matching checkType */      /* check all the lines matching checkType */
2038      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2039   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
2040       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
2041       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2042   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
2043        ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2044     line = getLineByType(ct, line);
2045     if (!line)
2046        break;  /* not found in this entry */
2047    
2048   if (line && line->type != LT_MENUENTRY &&   if (line && line->type != LT_MENUENTRY &&
2049   line->numElements >= 2) {   line->numElements >= 2) {
# Line 1765  struct singleEntry * findEntryByPath(str Line 2062  struct singleEntry * findEntryByPath(str
2062       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2063       * unfortunate)       * unfortunate)
2064       */       */
2065      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2066   break; /* found 'im! */   break; /* found 'im! */
2067   }   }
2068    
# Line 1775  struct singleEntry * findEntryByPath(str Line 2072  struct singleEntry * findEntryByPath(str
2072      return entry;      return entry;
2073  }  }
2074    
2075    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2076          int * index) {
2077        struct singleEntry * entry;
2078        struct singleLine * line;
2079        int i;
2080        char * newtitle;
2081    
2082        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2083     if (index && i < *index)
2084        continue;
2085     line = getLineByType(LT_TITLE, entry->lines);
2086     if (!line)
2087        line = getLineByType(LT_MENUENTRY, entry->lines);
2088     if (!line)
2089        continue;
2090     newtitle = grub2ExtractTitle(line);
2091     if (!newtitle)
2092        continue;
2093     if (!strcmp(title, newtitle))
2094        break;
2095        }
2096    
2097        if (!entry)
2098     return NULL;
2099    
2100        if (index)
2101     *index = i;
2102        return entry;
2103    }
2104    
2105  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2106      struct singleEntry * entry;      struct singleEntry * entry;
2107    
# Line 1797  struct singleEntry * findTemplate(struct Line 2124  struct singleEntry * findTemplate(struct
2124      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2125      int index;      int index;
2126    
2127      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2128     if (cfg->cfi->getEnv) {
2129        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2130        if (defTitle) {
2131     int index = 0;
2132     if (isnumber(defTitle)) {
2133        index = atoi(defTitle);
2134        entry = findEntryByIndex(cfg, index);
2135     } else {
2136        entry = findEntryByTitle(cfg, defTitle, &index);
2137     }
2138     if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2139        cfg->defaultImage = index;
2140        if (indexPtr)
2141     *indexPtr = index;
2142        return entry;
2143     }
2144        }
2145     }
2146        } else if (cfg->defaultImage > -1) {
2147   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2148   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2149      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1867  void markRemovedImage(struct grubConfig Line 2213  void markRemovedImage(struct grubConfig
2213    
2214  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2215       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2216       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2217      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2218      int i, j;      int i, j;
2219    
2220      if (newIsDefault) {      if (newIsDefault) {
2221   config->defaultImage = 0;   config->defaultImage = 0;
2222   return;   return;
2223        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2224     if (findEntryByIndex(config, index))
2225        config->defaultImage = index;
2226     else
2227        config->defaultImage = -1;
2228     return;
2229      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2230   i = 0;   i = 0;
2231   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1945  void displayEntry(struct singleEntry * e Line 2297  void displayEntry(struct singleEntry * e
2297      struct singleLine * line;      struct singleLine * line;
2298      char * root = NULL;      char * root = NULL;
2299      int i;      int i;
2300        int j;
2301    
2302      printf("index=%d\n", index);      printf("index=%d\n", index);
2303    
2304      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2305      if (!line) {      if (!line) {
2306          printf("non linux entry\n");          printf("non linux entry\n");
2307          return;          return;
2308      }      }
2309    
2310      printf("kernel=%s%s\n", prefix, line->elements[1].item);      if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2311     printf("kernel=%s\n", line->elements[1].item);
2312        else
2313     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2314    
2315      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2316   printf("args=\"");   printf("args=\"");
# Line 2010  void displayEntry(struct singleEntry * e Line 2366  void displayEntry(struct singleEntry * e
2366   printf("root=%s\n", s);   printf("root=%s\n", s);
2367      }      }
2368    
2369      line = getLineByType(LT_INITRD, entry->lines);      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2370    
2371      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2372   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2373        printf("initrd=");
2374     else
2375        printf("initrd=%s", prefix);
2376    
2377   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2378      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2379   printf("\n");   printf("\n");
# Line 2025  void displayEntry(struct singleEntry * e Line 2385  void displayEntry(struct singleEntry * e
2385      } else {      } else {
2386   char * title;   char * title;
2387   line = getLineByType(LT_MENUENTRY, entry->lines);   line = getLineByType(LT_MENUENTRY, entry->lines);
2388   title = grub2ExtractTitle(line);   if (line) {
2389   if (title)      title = grub2ExtractTitle(line);
2390      printf("title=%s\n", title);      if (title)
2391     printf("title=%s\n", title);
2392     }
2393        }
2394    
2395        for (j = 0, line = entry->lines; line; line = line->next) {
2396     if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
2397        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2398     printf("mbmodule%d=", j);
2399        else
2400     printf("mbmodule%d=%s", j, prefix);
2401    
2402        for (i = 1; i < line->numElements; i++)
2403     printf("%s%s", line->elements[i].item, line->elements[i].indent);
2404        printf("\n");
2405        j++;
2406     }
2407        }
2408    }
2409    
2410    int isSuseSystem(void) {
2411        const char * path;
2412        const static char default_path[] = "/etc/SuSE-release";
2413    
2414        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2415     path = default_path;
2416    
2417        if (!access(path, R_OK))
2418     return 1;
2419        return 0;
2420    }
2421    
2422    int isSuseGrubConf(const char * path) {
2423        FILE * grubConf;
2424        char * line = NULL;
2425        size_t len = 0, res = 0;
2426    
2427        grubConf = fopen(path, "r");
2428        if (!grubConf) {
2429            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2430     return 0;
2431        }
2432    
2433        while ((res = getline(&line, &len, grubConf)) != -1) {
2434     if (!strncmp(line, "setup", 5)) {
2435        fclose(grubConf);
2436        free(line);
2437        return 1;
2438     }
2439        }
2440    
2441        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2442          path);
2443    
2444        fclose(grubConf);
2445        free(line);
2446        return 0;
2447    }
2448    
2449    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2450        FILE * grubConf;
2451        char * line = NULL;
2452        size_t res = 0, len = 0;
2453    
2454        if (!path) return 1;
2455        if (!lbaPtr) return 1;
2456    
2457        grubConf = fopen(path, "r");
2458        if (!grubConf) return 1;
2459    
2460        while ((res = getline(&line, &len, grubConf)) != -1) {
2461     if (line[res - 1] == '\n')
2462        line[res - 1] = '\0';
2463     else if (len > res)
2464        line[res] = '\0';
2465     else {
2466        line = realloc(line, res + 1);
2467        line[res] = '\0';
2468     }
2469    
2470     if (!strncmp(line, "setup", 5)) {
2471        if (strstr(line, "--force-lba")) {
2472            *lbaPtr = 1;
2473        } else {
2474            *lbaPtr = 0;
2475        }
2476        dbgPrintf("lba: %i\n", *lbaPtr);
2477        break;
2478     }
2479        }
2480    
2481        free(line);
2482        fclose(grubConf);
2483        return 0;
2484    }
2485    
2486    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2487        FILE * grubConf;
2488        char * line = NULL;
2489        size_t res = 0, len = 0;
2490        char * lastParamPtr = NULL;
2491        char * secLastParamPtr = NULL;
2492        char installDeviceNumber = '\0';
2493        char * bounds = NULL;
2494    
2495        if (!path) return 1;
2496        if (!devicePtr) return 1;
2497    
2498        grubConf = fopen(path, "r");
2499        if (!grubConf) return 1;
2500    
2501        while ((res = getline(&line, &len, grubConf)) != -1) {
2502     if (strncmp(line, "setup", 5))
2503        continue;
2504    
2505     if (line[res - 1] == '\n')
2506        line[res - 1] = '\0';
2507     else if (len > res)
2508        line[res] = '\0';
2509     else {
2510        line = realloc(line, res + 1);
2511        line[res] = '\0';
2512     }
2513    
2514     lastParamPtr = bounds = line + res;
2515    
2516     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2517     while (!isspace(*lastParamPtr))
2518        lastParamPtr--;
2519     lastParamPtr++;
2520    
2521     secLastParamPtr = lastParamPtr - 2;
2522     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2523    
2524     if (lastParamPtr + 3 > bounds) {
2525        dbgPrintf("lastParamPtr going over boundary");
2526        fclose(grubConf);
2527        free(line);
2528        return 1;
2529     }
2530     if (!strncmp(lastParamPtr, "(hd", 3))
2531        lastParamPtr += 3;
2532     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2533    
2534     /*
2535     * Second last parameter will decide wether last parameter is
2536     * an IMAGE_DEVICE or INSTALL_DEVICE
2537     */
2538     while (!isspace(*secLastParamPtr))
2539        secLastParamPtr--;
2540     secLastParamPtr++;
2541    
2542     if (secLastParamPtr + 3 > bounds) {
2543        dbgPrintf("secLastParamPtr going over boundary");
2544        fclose(grubConf);
2545        free(line);
2546        return 1;
2547     }
2548     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2549     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2550        secLastParamPtr += 3;
2551        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2552        installDeviceNumber = *secLastParamPtr;
2553     } else {
2554        installDeviceNumber = *lastParamPtr;
2555     }
2556    
2557     *devicePtr = malloc(6);
2558     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2559     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2560     fclose(grubConf);
2561     free(line);
2562     return 0;
2563      }      }
2564    
2565        free(line);
2566        fclose(grubConf);
2567        return 1;
2568    }
2569    
2570    int grubGetBootFromDeviceMap(const char * device,
2571         char ** bootPtr) {
2572        FILE * deviceMap;
2573        char * line = NULL;
2574        size_t res = 0, len = 0;
2575        char * devicePtr;
2576        char * bounds = NULL;
2577        const char * path;
2578        const static char default_path[] = "/boot/grub/device.map";
2579    
2580        if (!device) return 1;
2581        if (!bootPtr) return 1;
2582    
2583        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2584     path = default_path;
2585    
2586        dbgPrintf("opening grub device.map file from: %s\n", path);
2587        deviceMap = fopen(path, "r");
2588        if (!deviceMap)
2589     return 1;
2590    
2591        while ((res = getline(&line, &len, deviceMap)) != -1) {
2592            if (!strncmp(line, "#", 1))
2593        continue;
2594    
2595     if (line[res - 1] == '\n')
2596        line[res - 1] = '\0';
2597     else if (len > res)
2598        line[res] = '\0';
2599     else {
2600        line = realloc(line, res + 1);
2601        line[res] = '\0';
2602     }
2603    
2604     devicePtr = line;
2605     bounds = line + res;
2606    
2607     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2608        devicePtr++;
2609     dbgPrintf("device: %s\n", devicePtr);
2610    
2611     if (!strncmp(devicePtr, device, strlen(device))) {
2612        devicePtr += strlen(device);
2613        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2614            devicePtr++;
2615    
2616        *bootPtr = strdup(devicePtr);
2617        break;
2618     }
2619        }
2620    
2621        free(line);
2622        fclose(deviceMap);
2623        return 0;
2624    }
2625    
2626    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2627        char * grubDevice;
2628    
2629        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2630     dbgPrintf("error looking for grub installation device\n");
2631        else
2632     dbgPrintf("grubby installation device: %s\n", grubDevice);
2633    
2634        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2635     dbgPrintf("error looking for grub boot device\n");
2636        else
2637     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2638    
2639        free(grubDevice);
2640        return 0;
2641    }
2642    
2643    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2644        /*
2645         * This SuSE grub configuration file at this location is not your average
2646         * grub configuration file, but instead the grub commands used to setup
2647         * grub on that system.
2648         */
2649        const char * path;
2650        const static char default_path[] = "/etc/grub.conf";
2651    
2652        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2653     path = default_path;
2654    
2655        if (!isSuseGrubConf(path)) return 1;
2656    
2657        if (lbaPtr) {
2658            *lbaPtr = 0;
2659            if (suseGrubConfGetLba(path, lbaPtr))
2660                return 1;
2661        }
2662    
2663        if (bootPtr) {
2664            *bootPtr = NULL;
2665            suseGrubConfGetBoot(path, bootPtr);
2666        }
2667    
2668        return 0;
2669  }  }
2670    
2671  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 2079  int parseSysconfigGrub(int * lbaPtr, cha Line 2716  int parseSysconfigGrub(int * lbaPtr, cha
2716  }  }
2717    
2718  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2719      char * boot;      char * boot = NULL;
2720      int lba;      int lba;
2721    
2722      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2723   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2724   if (boot) printf("boot=%s\n", boot);      free(boot);
2725        return;
2726     }
2727        } else {
2728            if (parseSysconfigGrub(&lba, &boot)) {
2729        free(boot);
2730        return;
2731     }
2732        }
2733    
2734        if (lba) printf("lba\n");
2735        if (boot) {
2736     printf("boot=%s\n", boot);
2737     free(boot);
2738      }      }
2739  }  }
2740    
# Line 2133  struct singleLine * addLineTmpl(struct s Line 2783  struct singleLine * addLineTmpl(struct s
2783  {  {
2784      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2785    
2786        if (isEfi && cfi == &grub2ConfigType) {
2787     enum lineType_e old = newLine->type;
2788     newLine->type = preferredLineType(newLine->type, cfi);
2789     if (old != newLine->type)
2790        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2791        }
2792    
2793      if (val) {      if (val) {
2794   /* override the inherited value with our own.   /* override the inherited value with our own.
2795   * This is a little weak because it only applies to elements[1]   * This is a little weak because it only applies to elements[1]
# Line 2142  struct singleLine * addLineTmpl(struct s Line 2799  struct singleLine * addLineTmpl(struct s
2799   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2800    
2801   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2802   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2803      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2804      if (rootspec != NULL) {      if (rootspec != NULL) {
2805   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 2179  struct singleLine *  addLine(struct sing Line 2836  struct singleLine *  addLine(struct sing
2836      /* NB: This function shouldn't allocate items on the heap, rather on the      /* NB: This function shouldn't allocate items on the heap, rather on the
2837       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2838       */       */
   
2839      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2840   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2841   tmpl.type = type;   tmpl.type = type;
# Line 2513  int updateActualImage(struct grubConfig Line 3169  int updateActualImage(struct grubConfig
3169      firstElement = 2;      firstElement = 2;
3170    
3171   } else {   } else {
3172      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3173      if (!line) {      if (!line) {
3174   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3175   continue;   continue;
# Line 2669  int updateImage(struct grubConfig * cfg, Line 3325  int updateImage(struct grubConfig * cfg,
3325      return rc;      return rc;
3326  }  }
3327    
3328    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3329     const char * image, const char * prefix, const char * initrd,
3330     const char * title) {
3331        struct singleEntry * entry;
3332        struct singleLine * line, * kernelLine, *endLine = NULL;
3333        int index = 0;
3334    
3335        if (!image) return 0;
3336    
3337        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3338            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3339            if (!kernelLine) continue;
3340    
3341     /* if title is supplied, the entry's title must match it. */
3342     if (title) {
3343        char *linetitle;
3344    
3345        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3346        if (!line)
3347     continue;
3348    
3349        linetitle = extractTitle(cfg, line);
3350        if (!linetitle)
3351     continue;
3352        if (strcmp(title, linetitle)) {
3353     free(linetitle);
3354     continue;
3355        }
3356        free(linetitle);
3357     }
3358    
3359            if (prefix) {
3360                int prefixLen = strlen(prefix);
3361                if (!strncmp(initrd, prefix, prefixLen))
3362                    initrd += prefixLen;
3363            }
3364     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3365     if (endLine)
3366        removeLine(entry, endLine);
3367            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3368     kernelLine->indent, initrd);
3369            if (!line)
3370        return 1;
3371     if (endLine) {
3372        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3373                if (!line)
3374     return 1;
3375     }
3376    
3377            break;
3378        }
3379    
3380        return 0;
3381    }
3382    
3383  int updateInitrd(struct grubConfig * cfg, const char * image,  int updateInitrd(struct grubConfig * cfg, const char * image,
3384                   const char * prefix, const char * initrd) {                   const char * prefix, const char * initrd, const char * title) {
3385      struct singleEntry * entry;      struct singleEntry * entry;
3386      struct singleLine * line, * kernelLine, *endLine = NULL;      struct singleLine * line, * kernelLine, *endLine = NULL;
3387      int index = 0;      int index = 0;
# Line 2678  int updateInitrd(struct grubConfig * cfg Line 3389  int updateInitrd(struct grubConfig * cfg
3389      if (!image) return 0;      if (!image) return 0;
3390    
3391      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3392          kernelLine = getLineByType(LT_KERNEL, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3393          if (!kernelLine) continue;          if (!kernelLine) continue;
3394    
3395          line = getLineByType(LT_INITRD, entry->lines);   /* if title is supplied, the entry's title must match it. */
3396     if (title) {
3397        char *linetitle;
3398    
3399        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3400        if (!line)
3401     continue;
3402    
3403        linetitle = extractTitle(cfg, line);
3404        if (!linetitle)
3405     continue;
3406        if (strcmp(title, linetitle)) {
3407     free(linetitle);
3408     continue;
3409        }
3410        free(linetitle);
3411     }
3412    
3413            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3414          if (line)          if (line)
3415              removeLine(entry, line);              removeLine(entry, line);
3416          if (prefix) {          if (prefix) {
# Line 2692  int updateInitrd(struct grubConfig * cfg Line 3421  int updateInitrd(struct grubConfig * cfg
3421   endLine = getLineByType(LT_ENTRY_END, entry->lines);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3422   if (endLine)   if (endLine)
3423      removeLine(entry, endLine);      removeLine(entry, endLine);
3424          line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);   enum lineType_e lt;
3425     switch(kernelLine->type) {
3426        case LT_KERNEL:
3427            lt = LT_INITRD;
3428     break;
3429        case LT_KERNEL_EFI:
3430            lt = LT_INITRD_EFI;
3431     break;
3432        case LT_KERNEL_16:
3433            lt = LT_INITRD_16;
3434     break;
3435        default:
3436            lt = preferredLineType(LT_INITRD, cfg->cfi);
3437     }
3438            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3439          if (!line)          if (!line)
3440      return 1;      return 1;
3441   if (endLine) {   if (endLine) {
# Line 2898  int checkForGrub(struct grubConfig * con Line 3641  int checkForGrub(struct grubConfig * con
3641      int fd;      int fd;
3642      unsigned char bootSect[512];      unsigned char bootSect[512];
3643      char * boot;      char * boot;
3644        int onSuse = isSuseSystem();
3645    
3646      if (parseSysconfigGrub(NULL, &boot))  
3647   return 0;      if (onSuse) {
3648     if (parseSuseGrubConf(NULL, &boot))
3649        return 0;
3650        } else {
3651     if (parseSysconfigGrub(NULL, &boot))
3652        return 0;
3653        }
3654    
3655      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3656      if (!boot)      if (!boot)
# Line 2919  int checkForGrub(struct grubConfig * con Line 3669  int checkForGrub(struct grubConfig * con
3669      }      }
3670      close(fd);      close(fd);
3671    
3672        /* The more elaborate checks do not work on SuSE. The checks done
3673         * seem to be reasonble (at least for now), so just return success
3674         */
3675        if (onSuse)
3676     return 2;
3677    
3678      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3679  }  }
3680    
# Line 2952  int checkForExtLinux(struct grubConfig * Line 3708  int checkForExtLinux(struct grubConfig *
3708      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3709  }  }
3710    
3711    int checkForYaboot(struct grubConfig * config) {
3712        /*
3713         * This is a simplistic check that we consider good enough for own puporses
3714         *
3715         * If we were to properly check if yaboot is *installed* we'd need to:
3716         * 1) get the system boot device (LT_BOOT)
3717         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3718         *    the content on the boot device
3719         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3720         * 4) check again if binary and boot device contents match
3721         */
3722        if (!access("/etc/yaboot.conf", R_OK))
3723     return 2;
3724    
3725        return 1;
3726    }
3727    
3728    int checkForElilo(struct grubConfig * config) {
3729        if (!access("/etc/elilo.conf", R_OK))
3730     return 2;
3731    
3732        return 1;
3733    }
3734    
3735  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3736      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3737    
# Line 3014  int addNewKernel(struct grubConfig * con Line 3794  int addNewKernel(struct grubConfig * con
3794   const char * newKernelPath, const char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3795   const char * newKernelArgs, const char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3796   const char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3797                   const char * newMBKernel, const char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3798     const char * newDevTreePath) {
3799      struct singleEntry * new;      struct singleEntry * new;
3800      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3801      int needs;      int needs;
# Line 3055  int addNewKernel(struct grubConfig * con Line 3836  int addNewKernel(struct grubConfig * con
3836          needs |= NEED_MB;          needs |= NEED_MB;
3837          new->multiboot = 1;          new->multiboot = 1;
3838      }      }
3839        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3840     needs |= NEED_DEVTREE;
3841    
3842      if (template) {      if (template) {
3843   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 3068  int addNewKernel(struct grubConfig * con Line 3851  int addNewKernel(struct grubConfig * con
3851      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3852      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3853    
3854      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
     tmplLine->numElements >= 2) {  
3855   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3856      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3857       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 3146  int addNewKernel(struct grubConfig * con Line 3928  int addNewKernel(struct grubConfig * con
3928      /* template is multi but new is not,      /* template is multi but new is not,
3929       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3930       */       */
3931      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3932      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3933      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3934   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3935     config->cfi)->key);
3936      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3937    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3938      config->cfi);
3939      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3940   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3941      char *initrdVal;      char *initrdVal;
3942      /* template is multi but new is not,      /* template is multi but new is not,
3943       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3944       */       */
3945      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3946      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3947      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3948   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3949     config->cfi)->key);
3950      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3951      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3952      free(initrdVal);      free(initrdVal);
3953      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3954   }   }
3955    
3956      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3957   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3958      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3959      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 3223  int addNewKernel(struct grubConfig * con Line 4007  int addNewKernel(struct grubConfig * con
4007      static const char *prefix = "'Loading ";      static const char *prefix = "'Loading ";
4008      if (tmplLine->numElements > 1 &&      if (tmplLine->numElements > 1 &&
4009      strstr(tmplLine->elements[1].item, prefix) &&      strstr(tmplLine->elements[1].item, prefix) &&
4010      masterLine->next && masterLine->next->type == LT_KERNEL) {      masterLine->next &&
4011        iskernel(masterLine->next->type)) {
4012   char *newTitle = malloc(strlen(prefix) +   char *newTitle = malloc(strlen(prefix) +
4013   strlen(newKernelTitle) + 2);   strlen(newKernelTitle) + 2);
4014    
# Line 3238  int addNewKernel(struct grubConfig * con Line 4023  int addNewKernel(struct grubConfig * con
4023   newLine = addLineTmpl(new, tmplLine, newLine, NULL,   newLine = addLineTmpl(new, tmplLine, newLine, NULL,
4024   config->cfi);   config->cfi);
4025      }      }
4026        } else if (tmplLine->type == LT_DEVTREE &&
4027           tmplLine->numElements == 2 && newDevTreePath) {
4028            newLine = addLineTmpl(new, tmplLine, newLine,
4029          newDevTreePath + strlen(prefix),
4030          config->cfi);
4031     needs &= ~NEED_DEVTREE;
4032        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
4033     const char *ndtp = newDevTreePath;
4034     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
4035        ndtp += strlen(prefix);
4036     newLine = addLine(new, config->cfi, LT_DEVTREE,
4037      config->secondaryIndent,
4038      ndtp);
4039     needs &= ~NEED_DEVTREE;
4040     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4041      } else {      } else {
4042   /* pass through other lines from the template */   /* pass through other lines from the template */
4043   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 3250  int addNewKernel(struct grubConfig * con Line 4050  int addNewKernel(struct grubConfig * con
4050   */   */
4051   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
4052      case LT_KERNEL:      case LT_KERNEL:
4053        case LT_KERNEL_EFI:
4054        case LT_KERNEL_16:
4055   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
4056      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
4057   } else {   } else {
4058      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
4059              preferredLineType(LT_KERNEL, config->cfi),
4060        config->primaryIndent,        config->primaryIndent,
4061        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
4062      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 3310  int addNewKernel(struct grubConfig * con Line 4113  int addNewKernel(struct grubConfig * con
4113   }   }
4114      }      }
4115    
4116        struct singleLine *endLine = NULL;
4117        endLine = getLineByType(LT_ENTRY_END, new->lines);
4118        if (endLine) {
4119        removeLine(new, endLine);
4120        needs |= NEED_END;
4121        }
4122    
4123      /* add the remainder of the lines, i.e. those that either      /* add the remainder of the lines, i.e. those that either
4124       * weren't present in the template, or in the case of no template,       * weren't present in the template, or in the case of no template,
4125       * all the lines following the entryStart.       * all the lines following the entryStart.
# Line 3329  int addNewKernel(struct grubConfig * con Line 4139  int addNewKernel(struct grubConfig * con
4139      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
4140   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4141    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4142        config->cfi)) ?        config->cfi))
4143    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
4144     : preferredLineType(LT_KERNEL, config->cfi),
4145    config->secondaryIndent,    config->secondaryIndent,
4146    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
4147   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 3346  int addNewKernel(struct grubConfig * con Line 4157  int addNewKernel(struct grubConfig * con
4157   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4158   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4159    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4160        config->cfi)) ?        config->cfi))
4161    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
4162       : preferredLineType(LT_INITRD, config->cfi),
4163    config->secondaryIndent,    config->secondaryIndent,
4164    initrdVal);    initrdVal);
4165   free(initrdVal);   free(initrdVal);
4166   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4167      }      }
4168        if (needs & NEED_DEVTREE) {
4169     newLine = addLine(new, config->cfi, LT_DEVTREE,
4170      config->secondaryIndent,
4171      newDevTreePath);
4172     needs &= ~NEED_DEVTREE;
4173        }
4174    
4175        /* NEEDS_END must be last on bootloaders that need it... */
4176      if (needs & NEED_END) {      if (needs & NEED_END) {
4177   newLine = addLine(new, config->cfi, LT_ENTRY_END,   newLine = addLine(new, config->cfi, LT_ENTRY_END,
4178   config->secondaryIndent, NULL);   config->secondaryIndent, NULL);
# Line 3379  static void traceback(int signum) Line 4199  static void traceback(int signum)
4199      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
4200      size = backtrace(array, 40);      size = backtrace(array, 40);
4201    
4202      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4203              (unsigned long)size);              (unsigned long)size);
4204      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
4205      exit(1);      exit(1);
# Line 3404  int main(int argc, const char ** argv) { Line 4224  int main(int argc, const char ** argv) {
4224      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4225      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4226      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4227      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4228      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4229      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4230      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 3414  int main(int argc, const char ** argv) { Line 4234  int main(int argc, const char ** argv) {
4234      char * removeArgs = NULL;      char * removeArgs = NULL;
4235      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4236      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4237        char * envPath = NULL;
4238      const char * chptr = NULL;      const char * chptr = NULL;
4239      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4240      struct grubConfig * config;      struct grubConfig * config;
# Line 3422  int main(int argc, const char ** argv) { Line 4243  int main(int argc, const char ** argv) {
4243      int displayDefault = 0;      int displayDefault = 0;
4244      int displayDefaultIndex = 0;      int displayDefaultIndex = 0;
4245      int displayDefaultTitle = 0;      int displayDefaultTitle = 0;
4246        int defaultIndex = -1;
4247      struct poptOption options[] = {      struct poptOption options[] = {
4248   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4249      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 3439  int main(int argc, const char ** argv) { Line 4261  int main(int argc, const char ** argv) {
4261   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4262      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4263      _("bootfs") },      _("bootfs") },
4264  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4265   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4266      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4267  #endif  #endif
4268   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4269      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 3460  int main(int argc, const char ** argv) { Line 4282  int main(int argc, const char ** argv) {
4282      _("display the index of the default kernel") },      _("display the index of the default kernel") },
4283   { "default-title", 0, 0, &displayDefaultTitle, 0,   { "default-title", 0, 0, &displayDefaultTitle, 0,
4284      _("display the title of the default kernel") },      _("display the title of the default kernel") },
4285     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4286        _("device tree file for new stanza"), _("dtb-path") },
4287     { "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4288        _("device tree directory for new stanza"), _("dtb-path") },
4289   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4290      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4291     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4292        _("force grub2 stanzas to use efi") },
4293     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4294        _("path for environment data"),
4295        _("path") },
4296   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4297      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4298   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
# Line 3474  int main(int argc, const char ** argv) { Line 4305  int main(int argc, const char ** argv) {
4305   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4306      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4307   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4308      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4309   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4310      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4311   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 3494  int main(int argc, const char ** argv) { Line 4325  int main(int argc, const char ** argv) {
4325   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4326      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4327        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4328     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4329        _("make the given entry index the default entry"),
4330        _("entry-index") },
4331   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4332      _("configure silo bootloader") },      _("configure silo bootloader") },
4333   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 3515  int main(int argc, const char ** argv) { Line 4349  int main(int argc, const char ** argv) {
4349    
4350      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4351    
4352        int i = 0;
4353        for (int j = 1; j < argc; j++)
4354     i += strlen(argv[j]) + 1;
4355        saved_command_line = malloc(i);
4356        if (!saved_command_line) {
4357     fprintf(stderr, "grubby: %m\n");
4358     exit(1);
4359        }
4360        saved_command_line[0] = '\0';
4361        for (int j = 1; j < argc; j++) {
4362     strcat(saved_command_line, argv[j]);
4363     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4364        }
4365    
4366      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4367      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4368    
# Line 3558  int main(int argc, const char ** argv) { Line 4406  int main(int argc, const char ** argv) {
4406   return 1;   return 1;
4407      } else if (configureGrub2) {      } else if (configureGrub2) {
4408   cfi = &grub2ConfigType;   cfi = &grub2ConfigType;
4409     if (envPath)
4410        cfi->envFile = envPath;
4411      } else if (configureLilo) {      } else if (configureLilo) {
4412   cfi = &liloConfigType;   cfi = &liloConfigType;
4413      } else if (configureGrub) {      } else if (configureGrub) {
# Line 3601  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 3619  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 3645  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 3653  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 3681  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 3710  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 3737  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 3755  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 3777  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 3790  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.1846  
changed lines
  Added in v.2980