Magellan Linux

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

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

trunk/grubby/grubby.c revision 1849 by niro, Mon Jul 2 13:08:29 2012 UTC tags/grubby-8_32/grubby.c revision 2703 by niro, Wed Jul 16 10:52:43 2014 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 205  struct keywordTypes grub2Keywords[] = { Line 233  struct keywordTypes grub2Keywords[] = {
233      { "default",    LT_DEFAULT,     ' ' },      { "default",    LT_DEFAULT,     ' ' },
234      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
235      { "linux",      LT_KERNEL,      ' ' },      { "linux",      LT_KERNEL,      ' ' },
236        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
237        { "linux16",    LT_KERNEL_16,   ' ' },
238      { "initrd",     LT_INITRD,      ' ', ' ' },      { "initrd",     LT_INITRD,      ' ', ' ' },
239        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
240        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
241      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
242      { "kernel",     LT_HYPER,       ' ' },      { "kernel",     LT_HYPER,       ' ' },
243        { "devicetree", LT_DEVTREE,  ' ' },
244      { NULL, 0, 0 },      { NULL, 0, 0 },
245  };  };
246    
# Line 219  const char *grub2FindConfig(struct confi Line 252  const char *grub2FindConfig(struct confi
252      };      };
253      static int i = -1;      static int i = -1;
254      static const char *grub_cfg = "/boot/grub/grub.cfg";      static const char *grub_cfg = "/boot/grub/grub.cfg";
255        int rc = -1;
256    
257      if (i == -1) {      if (i == -1) {
258   for (i = 0; configFiles[i] != NULL; i++) {   for (i = 0; configFiles[i] != NULL; i++) {
259      dbgPrintf("Checking \"%s\": ", configFiles[i]);      dbgPrintf("Checking \"%s\": ", configFiles[i]);
260      if (!access(configFiles[i], R_OK)) {      if ((rc = access(configFiles[i], R_OK))) {
261     if (errno == EACCES) {
262        printf("Unable to access bootloader configuration file "
263           "\"%s\": %m\n", configFiles[i]);
264        exit(1);
265     }
266     continue;
267        } else {
268   dbgPrintf("found\n");   dbgPrintf("found\n");
269   return configFiles[i];   return configFiles[i];
270      }      }
# Line 242  const char *grub2FindConfig(struct confi Line 283  const char *grub2FindConfig(struct confi
283      return configFiles[i];      return configFiles[i];
284  }  }
285    
286    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
287    static char *grub2GetEnv(struct configFileInfo *info, char *name)
288    {
289        static char buf[1025];
290        char *s = NULL;
291        char *ret = NULL;
292        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
293        int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name);
294    
295        if (rc < 0)
296     return NULL;
297    
298        FILE *f = popen(s, "r");
299        if (!f)
300     goto out;
301    
302        memset(buf, '\0', sizeof (buf));
303        ret = fgets(buf, 1024, f);
304        pclose(f);
305    
306        if (ret) {
307     ret += strlen(name) + 1;
308     ret[strlen(ret) - 1] = '\0';
309        }
310        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
311    out:
312        free(s);
313        return ret;
314    }
315    
316    static int sPopCount(const char *s, const char *c)
317    {
318        int ret = 0;
319        if (!s)
320     return -1;
321        for (int i = 0; s[i] != '\0'; i++)
322     for (int j = 0; c[j] != '\0'; j++)
323        if (s[i] == c[j])
324     ret++;
325        return ret;
326    }
327    
328    static char *shellEscape(const char *s)
329    {
330        int l = strlen(s) + sPopCount(s, "'") * 2;
331    
332        char *ret = calloc(l+1, sizeof (*ret));
333        if (!ret)
334     return NULL;
335        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
336     if (s[i] == '\'')
337        ret[j++] = '\\';
338     ret[j] = s[i];
339        }
340        return ret;
341    }
342    
343    static void unquote(char *s)
344    {
345        int l = strlen(s);
346    
347        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
348     memmove(s, s+1, l-2);
349     s[l-2] = '\0';
350        }
351    }
352    
353    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
354    {
355        char *s = NULL;
356        int rc = 0;
357        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
358    
359        unquote(value);
360        value = shellEscape(value);
361        if (!value)
362        return -1;
363    
364        rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value);
365        free(value);
366        if (rc <0)
367     return -1;
368    
369        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
370        rc = system(s);
371        free(s);
372        return rc;
373    }
374    
375    /* this is a gigantic hack to avoid clobbering grub2 variables... */
376    static int is_special_grub2_variable(const char *name)
377    {
378        if (!strcmp(name,"\"${next_entry}\""))
379     return 1;
380        if (!strcmp(name,"\"${prev_saved_entry}\""))
381     return 1;
382        return 0;
383    }
384    
385  int sizeOfSingleLine(struct singleLine * line) {  int sizeOfSingleLine(struct singleLine * line) {
386    int count = 0;    int count = 0;
387    
# Line 271  static int isquote(char q) Line 411  static int isquote(char q)
411      return 0;      return 0;
412  }  }
413    
414    static int iskernel(enum lineType_e type) {
415        return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
416    }
417    
418    static int isinitrd(enum lineType_e type) {
419        return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
420    }
421    
422  char *grub2ExtractTitle(struct singleLine * line) {  char *grub2ExtractTitle(struct singleLine * line) {
423      char * current;      char * current;
424      char * current_indent;      char * current_indent;
# Line 328  char *grub2ExtractTitle(struct singleLin Line 476  char *grub2ExtractTitle(struct singleLin
476    
477  struct configFileInfo grub2ConfigType = {  struct configFileInfo grub2ConfigType = {
478      .findConfig = grub2FindConfig,      .findConfig = grub2FindConfig,
479        .getEnv = grub2GetEnv,
480        .setEnv = grub2SetEnv,
481      .keywords = grub2Keywords,      .keywords = grub2Keywords,
482      .defaultIsIndex = 1,      .defaultIsIndex = 1,
483      .defaultSupportSaved = 1,      .defaultSupportSaved = 1,
# Line 482  struct configFileInfo ziplConfigType = { Line 632  struct configFileInfo ziplConfigType = {
632  struct configFileInfo extlinuxConfigType = {  struct configFileInfo extlinuxConfigType = {
633      .defaultConfig = "/boot/extlinux/extlinux.conf",      .defaultConfig = "/boot/extlinux/extlinux.conf",
634      .keywords = extlinuxKeywords,      .keywords = extlinuxKeywords,
635        .caseInsensitive = 1,
636      .entryStart = LT_TITLE,      .entryStart = LT_TITLE,
637      .needsBootPrefix = 1,      .needsBootPrefix = 1,
638      .maxTitleLength = 255,      .maxTitleLength = 255,
639      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
640        .defaultIsUnquoted = 1,
641  };  };
642    
643  struct grubConfig {  struct grubConfig {
# Line 506  struct singleEntry * findEntryByIndex(st Line 658  struct singleEntry * findEntryByIndex(st
658  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
659       const char * path, const char * prefix,       const char * path, const char * prefix,
660       int * index);       int * index);
661    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
662          int * index);
663  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
664  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
665  struct singleLine * lineDup(struct singleLine * line);  struct singleLine * lineDup(struct singleLine * line);
# Line 570  static char * sdupprintf(const char *for Line 724  static char * sdupprintf(const char *for
724      return buf;      return buf;
725  }  }
726    
727    static enum lineType_e preferredLineType(enum lineType_e type,
728     struct configFileInfo *cfi) {
729        if (isEfi && cfi == &grub2ConfigType) {
730     switch (type) {
731     case LT_KERNEL:
732        return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
733     case LT_INITRD:
734        return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
735     default:
736        return type;
737     }
738    #if defined(__i386__) || defined(__x86_64__)
739        } else if (cfi == &grub2ConfigType) {
740     switch (type) {
741     case LT_KERNEL:
742        return LT_KERNEL_16;
743     case LT_INITRD:
744        return LT_INITRD_16;
745     default:
746        return type;
747     }
748    #endif
749        }
750        return type;
751    }
752    
753  static struct keywordTypes * getKeywordByType(enum lineType_e type,  static struct keywordTypes * getKeywordByType(enum lineType_e type,
754        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
755      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 783  static char * getuuidbydev(char *device)
783  static enum lineType_e getTypeByKeyword(char * keyword,  static enum lineType_e getTypeByKeyword(char * keyword,
784   struct configFileInfo * cfi) {   struct configFileInfo * cfi) {
785      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
786   if (!strcmp(keyword, kw->key))   if (cfi->caseInsensitive) {
787      return kw->type;      if (!strcasecmp(keyword, kw->key))
788                    return kw->type;
789     } else {
790        if (!strcmp(keyword, kw->key))
791            return kw->type;
792     }
793      }      }
794      return LT_UNKNOWN;      return LT_UNKNOWN;
795  }  }
# Line 643  static int isEntryStart(struct singleLin Line 828  static int isEntryStart(struct singleLin
828  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
829  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
830      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
831      char * title;      char * title = NULL;
832      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
833      title++;   title = strdup(line->elements[0].item);
834      *(title + strlen(title) - 1) = '\0';   title++;
835     *(title + strlen(title) - 1) = '\0';
836        } else if (line->type == LT_MENUENTRY)
837     title = strdup(line->elements[1].item);
838        else
839     return NULL;
840      return title;      return title;
841  }  }
842    
# Line 904  static int getNextLine(char ** bufPtr, s Line 1094  static int getNextLine(char ** bufPtr, s
1094      return 0;      return 0;
1095  }  }
1096    
1097    static int isnumber(const char *s)
1098    {
1099        int i;
1100        for (i = 0; s[i] != '\0'; i++)
1101     if (s[i] < '0' || s[i] > '9')
1102        return 0;
1103        return i;
1104    }
1105    
1106  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1107        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1108      int in;      int in;
# Line 918  static struct grubConfig * readConfig(co Line 1117  static struct grubConfig * readConfig(co
1117      int len;      int len;
1118      char * buf;      char * buf;
1119    
1120      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1121            printf("Could not find bootloader configuration\n");
1122            exit(1);
1123        } else if (!strcmp(inName, "-")) {
1124   in = 0;   in = 0;
1125      } else {      } else {
1126   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 985  static struct grubConfig * readConfig(co Line 1187  static struct grubConfig * readConfig(co
1187      dbgPrintf("\n");      dbgPrintf("\n");
1188      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1189      if (kwType && line->numElements == 3 &&      if (kwType && line->numElements == 3 &&
1190      !strcmp(line->elements[1].item, kwType->key)) {      !strcmp(line->elements[1].item, kwType->key) &&
1191        !is_special_grub2_variable(line->elements[2].item)) {
1192   dbgPrintf("Line sets default config\n");   dbgPrintf("Line sets default config\n");
1193   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1194   defaultLine = line;   defaultLine = line;
1195      }      }
  } else if (line->type == LT_DEFAULT && line->numElements == 2) {  
     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;  
     defaultLine = line;  
1196    
1197          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1198      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1199       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1200       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1201       */       */
1202      if (entry->multiboot)      if (entry && entry->multiboot)
1203   line->type = LT_HYPER;   line->type = LT_HYPER;
1204    
1205          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 1011  static struct grubConfig * readConfig(co Line 1211  static struct grubConfig * readConfig(co
1211      for (struct singleLine *l = entry->lines; l; l = l->next) {      for (struct singleLine *l = entry->lines; l; l = l->next) {
1212   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1213      break;      break;
1214   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1215      l->type = LT_HYPER;      l->type = LT_HYPER;
1216      break;      break;
1217   }   }
# Line 1025  static struct grubConfig * readConfig(co Line 1225  static struct grubConfig * readConfig(co
1225      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1226      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1227    
1228   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1229      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1230        /* make the title/default a single argument (undoing our parsing) */
1231      len = 0;      len = 0;
1232      for (int i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1233   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
# Line 1133  static struct grubConfig * readConfig(co Line 1334  static struct grubConfig * readConfig(co
1334      }      }
1335   }   }
1336    
1337     if (line->type == LT_DEFAULT && line->numElements == 2) {
1338        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1339        defaultLine = line;
1340     }
1341    
1342   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1343     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1344     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 1396  static struct grubConfig * readConfig(co
1396          if (defaultLine->numElements > 2 &&          if (defaultLine->numElements > 2 &&
1397      cfi->defaultSupportSaved &&      cfi->defaultSupportSaved &&
1398      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1399      cfg->defaultImage = DEFAULT_SAVED_GRUB2;   cfg->cfi->defaultIsSaved = 1;
1400     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1401     if (cfg->cfi->getEnv) {
1402        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1403        if (defTitle) {
1404     int index = 0;
1405     if (isnumber(defTitle)) {
1406        index = atoi(defTitle);
1407        entry = findEntryByIndex(cfg, index);
1408     } else {
1409        entry = findEntryByTitle(cfg, defTitle, &index);
1410     }
1411     if (entry)
1412        cfg->defaultImage = index;
1413        }
1414     }
1415   } else if (cfi->defaultIsVariable) {   } else if (cfi->defaultIsVariable) {
1416      char *value = defaultLine->elements[2].item;      char *value = defaultLine->elements[2].item;
1417      while (*value && (*value == '"' || *value == '\'' ||      while (*value && (*value == '"' || *value == '\'' ||
# Line 1231  static struct grubConfig * readConfig(co Line 1452  static struct grubConfig * readConfig(co
1452          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1453      }      }
1454   }   }
1455        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1456     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1457     if (defTitle) {
1458        int index = 0;
1459        if (isnumber(defTitle)) {
1460     index = atoi(defTitle);
1461     entry = findEntryByIndex(cfg, index);
1462        } else {
1463     entry = findEntryByTitle(cfg, defTitle, &index);
1464        }
1465        if (entry)
1466     cfg->defaultImage = index;
1467     }
1468      } else {      } else {
1469          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1470      }      }
# Line 1248  static void writeDefault(FILE * out, cha Line 1482  static void writeDefault(FILE * out, cha
1482    
1483      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1484   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1485      else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)      else if (cfg->cfi->defaultIsSaved) {
1486   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1487      else if (cfg->defaultImage > -1) {   if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1488        char *title;
1489        entry = findEntryByIndex(cfg, cfg->defaultImage);
1490        line = getLineByType(LT_MENUENTRY, entry->lines);
1491        if (!line)
1492     line = getLineByType(LT_TITLE, entry->lines);
1493        if (line) {
1494     title = extractTitle(line);
1495     if (title)
1496        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1497        }
1498     }
1499        } else if (cfg->defaultImage > -1) {
1500   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1501      if (cfg->cfi->defaultIsVariable) {      if (cfg->cfi->defaultIsVariable) {
1502          fprintf(out, "%sset default=\"%d\"\n", indent,          fprintf(out, "%sset default=\"%d\"\n", indent,
# Line 1310  static int writeConfig(struct grubConfig Line 1556  static int writeConfig(struct grubConfig
1556    
1557      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1558         directory to the dir of the symlink */         directory to the dir of the symlink */
1559              rc = chdir(dirname(outName));      char *dir = strdupa(outName);
1560        rc = chdir(dirname(dir));
1561      do {      do {
1562   buf = alloca(len + 1);   buf = alloca(len + 1);
1563   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1352  static int writeConfig(struct grubConfig Line 1599  static int writeConfig(struct grubConfig
1599      while (line) {      while (line) {
1600          if (line->type == LT_SET_VARIABLE && defaultKw &&          if (line->type == LT_SET_VARIABLE && defaultKw &&
1601   line->numElements == 3 &&   line->numElements == 3 &&
1602   !strcmp(line->elements[1].item, defaultKw->key)) {   !strcmp(line->elements[1].item, defaultKw->key) &&
1603     !is_special_grub2_variable(line->elements[2].item)) {
1604      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1605      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1606   } else if (line->type == LT_DEFAULT) {   } else if (line->type == LT_DEFAULT) {
# Line 1497  static char *findDiskForRoot() Line 1745  static char *findDiskForRoot()
1745      return NULL;      return NULL;
1746  }  }
1747    
1748  void printEntry(struct singleEntry * entry) {  void printEntry(struct singleEntry * entry, FILE *f) {
1749      int i;      int i;
1750      struct singleLine * line;      struct singleLine * line;
1751    
1752      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
1753   fprintf(stderr, "DBG: %s", line->indent);   log_message(f, "DBG: %s", line->indent);
1754   for (i = 0; i < line->numElements; i++) {   for (i = 0; i < line->numElements; i++) {
1755      /* Need to handle this, because we strip the quotes from      /* Need to handle this, because we strip the quotes from
1756       * menuentry when read it. */       * menuentry when read it. */
1757      if (line->type == LT_MENUENTRY && i == 1) {      if (line->type == LT_MENUENTRY && i == 1) {
1758   if(!isquote(*line->elements[i].item))   if(!isquote(*line->elements[i].item))
1759      fprintf(stderr, "\'%s\'", line->elements[i].item);      log_message(f, "\'%s\'", line->elements[i].item);
1760   else   else
1761      fprintf(stderr, "%s", line->elements[i].item);      log_message(f, "%s", line->elements[i].item);
1762   fprintf(stderr, "%s", line->elements[i].indent);   log_message(f, "%s", line->elements[i].indent);
1763    
1764   continue;   continue;
1765      }      }
1766            
1767      fprintf(stderr, "%s%s",      log_message(f, "%s%s",
1768      line->elements[i].item, line->elements[i].indent);      line->elements[i].item, line->elements[i].indent);
1769   }   }
1770   fprintf(stderr, "\n");   log_message(f, "\n");
1771      }      }
1772  }  }
1773    
1774  void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1775  {  {
1776      va_list argp;      static int once;
1777        va_list argp, argq;
1778    
1779        va_start(argp, fmt);
1780    
1781      if (!debug)      va_copy(argq, argp);
1782        if (!once) {
1783     log_time(NULL);
1784     log_message(NULL, "command line: %s\n", saved_command_line);
1785        }
1786        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1787        log_vmessage(NULL, fmt, argq);
1788    
1789        printEntry(entry, NULL);
1790        va_end(argq);
1791    
1792        if (!debug) {
1793     once = 1;
1794         va_end(argp);
1795   return;   return;
1796        }
1797    
1798      va_start(argp, fmt);      if (okay) {
1799     va_end(argp);
1800     return;
1801        }
1802    
1803        if (!once)
1804     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1805        once = 1;
1806      fprintf(stderr, "DBG: Image entry failed: ");      fprintf(stderr, "DBG: Image entry failed: ");
1807      vfprintf(stderr, fmt, argp);      vfprintf(stderr, fmt, argp);
1808      printEntry(entry);      printEntry(entry, stderr);
1809      va_end(argp);      va_end(argp);
1810  }  }
1811    
# Line 1560  int suitableImage(struct singleEntry * e Line 1832  int suitableImage(struct singleEntry * e
1832      char * rootdev;      char * rootdev;
1833    
1834      if (skipRemoved && entry->skip) {      if (skipRemoved && entry->skip) {
1835   notSuitablePrintf(entry, "marked to skip\n");   notSuitablePrintf(entry, 0, "marked to skip\n");
1836   return 0;   return 0;
1837      }      }
1838    
1839      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1840      if (!line) {      if (!line) {
1841   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1842   return 0;   return 0;
1843      }      }
1844      if (line->numElements < 2) {      if (line->numElements < 2) {
1845   notSuitablePrintf(entry, "line has only %d elements\n",   notSuitablePrintf(entry, 0, "line has only %d elements\n",
1846      line->numElements);      line->numElements);
1847   return 0;   return 0;
1848      }      }
1849    
1850      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1851        notSuitablePrintf(entry, 1, "\n");
1852        return 1;
1853        }
1854    
1855      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1856        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
# Line 1586  int suitableImage(struct singleEntry * e Line 1861  int suitableImage(struct singleEntry * e
1861      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1862              line->elements[1].item + rootspec_offset);              line->elements[1].item + rootspec_offset);
1863      if (access(fullName, R_OK)) {      if (access(fullName, R_OK)) {
1864   notSuitablePrintf(entry, "access to %s failed\n", fullName);   notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1865   return 0;   return 0;
1866      }      }
1867      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 1607  int suitableImage(struct singleEntry * e Line 1882  int suitableImage(struct singleEntry * e
1882    
1883              /* failed to find one */              /* failed to find one */
1884              if (!line) {              if (!line) {
1885   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1886   return 0;   return 0;
1887              }              }
1888    
# Line 1616  int suitableImage(struct singleEntry * e Line 1891  int suitableImage(struct singleEntry * e
1891      if (i < line->numElements)      if (i < line->numElements)
1892          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1893      else {      else {
1894   notSuitablePrintf(entry, "no root= entry found\n");   notSuitablePrintf(entry, 0, "no root= entry found\n");
1895   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1896          return 0;          return 0;
1897              }              }
# Line 1625  int suitableImage(struct singleEntry * e Line 1900  int suitableImage(struct singleEntry * e
1900    
1901      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1902      if (!getpathbyspec(dev)) {      if (!getpathbyspec(dev)) {
1903          notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);          notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1904          return 0;          return 0;
1905      } else      } else
1906   dev = getpathbyspec(dev);   dev = getpathbyspec(dev);
1907    
1908      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1909      if (!rootdev) {      if (!rootdev) {
1910          notSuitablePrintf(entry, "can't find root device\n");          notSuitablePrintf(entry, 0, "can't find root device\n");
1911   return 0;   return 0;
1912      }      }
1913    
1914      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1915          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1916   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1917          free(rootdev);          free(rootdev);
1918          return 0;          return 0;
1919      }      }
1920    
1921      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1922          notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1923   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1924   free(rootdev);   free(rootdev);
1925          return 0;          return 0;
1926      }      }
1927    
1928      free(rootdev);      free(rootdev);
1929        notSuitablePrintf(entry, 1, "\n");
1930    
1931      return 1;      return 1;
1932  }  }
# Line 1694  struct singleEntry * findEntryByPath(str Line 1970  struct singleEntry * findEntryByPath(str
1970   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1971   if (!entry) return NULL;   if (!entry) return NULL;
1972    
1973   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1974   if (!line) return NULL;   if (!line) return NULL;
1975    
1976   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1743  struct singleEntry * findEntryByPath(str Line 2019  struct singleEntry * findEntryByPath(str
2019    
2020      /* check all the lines matching checkType */      /* check all the lines matching checkType */
2021      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2022   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
2023       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
2024       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2025   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
2026        ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2027     line = getLineByType(ct, line);
2028     if (!line)
2029        break;  /* not found in this entry */
2030    
2031   if (line && line->type != LT_MENUENTRY &&   if (line && line->type != LT_MENUENTRY &&
2032   line->numElements >= 2) {   line->numElements >= 2) {
# Line 1765  struct singleEntry * findEntryByPath(str Line 2045  struct singleEntry * findEntryByPath(str
2045       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2046       * unfortunate)       * unfortunate)
2047       */       */
2048      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2049   break; /* found 'im! */   break; /* found 'im! */
2050   }   }
2051    
# Line 1775  struct singleEntry * findEntryByPath(str Line 2055  struct singleEntry * findEntryByPath(str
2055      return entry;      return entry;
2056  }  }
2057    
2058    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2059          int * index) {
2060        struct singleEntry * entry;
2061        struct singleLine * line;
2062        int i;
2063        char * newtitle;
2064    
2065        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2066     if (index && i < *index)
2067        continue;
2068     line = getLineByType(LT_TITLE, entry->lines);
2069     if (!line)
2070        line = getLineByType(LT_MENUENTRY, entry->lines);
2071     if (!line)
2072        continue;
2073     newtitle = grub2ExtractTitle(line);
2074     if (!newtitle)
2075        continue;
2076     if (!strcmp(title, newtitle))
2077        break;
2078        }
2079    
2080        if (!entry)
2081     return NULL;
2082    
2083        if (index)
2084     *index = i;
2085        return entry;
2086    }
2087    
2088  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2089      struct singleEntry * entry;      struct singleEntry * entry;
2090    
# Line 1797  struct singleEntry * findTemplate(struct Line 2107  struct singleEntry * findTemplate(struct
2107      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2108      int index;      int index;
2109    
2110      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2111     if (cfg->cfi->getEnv) {
2112        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2113        if (defTitle) {
2114     int index = 0;
2115     if (isnumber(defTitle)) {
2116        index = atoi(defTitle);
2117        entry = findEntryByIndex(cfg, index);
2118     } else {
2119        entry = findEntryByTitle(cfg, defTitle, &index);
2120     }
2121     if (entry)
2122        cfg->defaultImage = index;
2123        }
2124     }
2125        } else if (cfg->defaultImage > -1) {
2126   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2127   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2128      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1867  void markRemovedImage(struct grubConfig Line 2192  void markRemovedImage(struct grubConfig
2192    
2193  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2194       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2195       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2196      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2197      int i, j;      int i, j;
2198    
2199      if (newIsDefault) {      if (newIsDefault) {
2200   config->defaultImage = 0;   config->defaultImage = 0;
2201   return;   return;
2202        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2203     if (findEntryByIndex(config, index))
2204        config->defaultImage = index;
2205     else
2206        config->defaultImage = -1;
2207     return;
2208      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2209   i = 0;   i = 0;
2210   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1948  void displayEntry(struct singleEntry * e Line 2279  void displayEntry(struct singleEntry * e
2279    
2280      printf("index=%d\n", index);      printf("index=%d\n", index);
2281    
2282      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2283      if (!line) {      if (!line) {
2284          printf("non linux entry\n");          printf("non linux entry\n");
2285          return;          return;
# Line 2013  void displayEntry(struct singleEntry * e Line 2344  void displayEntry(struct singleEntry * e
2344   printf("root=%s\n", s);   printf("root=%s\n", s);
2345      }      }
2346    
2347      line = getLineByType(LT_INITRD, entry->lines);      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2348    
2349      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2350   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
# Line 2038  void displayEntry(struct singleEntry * e Line 2369  void displayEntry(struct singleEntry * e
2369      }      }
2370  }  }
2371    
2372    int isSuseSystem(void) {
2373        const char * path;
2374        const static char default_path[] = "/etc/SuSE-release";
2375    
2376        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2377     path = default_path;
2378    
2379        if (!access(path, R_OK))
2380     return 1;
2381        return 0;
2382    }
2383    
2384    int isSuseGrubConf(const char * path) {
2385        FILE * grubConf;
2386        char * line = NULL;
2387        size_t len = 0, res = 0;
2388    
2389        grubConf = fopen(path, "r");
2390        if (!grubConf) {
2391            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2392     return 0;
2393        }
2394    
2395        while ((res = getline(&line, &len, grubConf)) != -1) {
2396     if (!strncmp(line, "setup", 5)) {
2397        fclose(grubConf);
2398        free(line);
2399        return 1;
2400     }
2401        }
2402    
2403        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2404          path);
2405    
2406        fclose(grubConf);
2407        free(line);
2408        return 0;
2409    }
2410    
2411    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2412        FILE * grubConf;
2413        char * line = NULL;
2414        size_t res = 0, len = 0;
2415    
2416        if (!path) return 1;
2417        if (!lbaPtr) return 1;
2418    
2419        grubConf = fopen(path, "r");
2420        if (!grubConf) return 1;
2421    
2422        while ((res = getline(&line, &len, grubConf)) != -1) {
2423     if (line[res - 1] == '\n')
2424        line[res - 1] = '\0';
2425     else if (len > res)
2426        line[res] = '\0';
2427     else {
2428        line = realloc(line, res + 1);
2429        line[res] = '\0';
2430     }
2431    
2432     if (!strncmp(line, "setup", 5)) {
2433        if (strstr(line, "--force-lba")) {
2434            *lbaPtr = 1;
2435        } else {
2436            *lbaPtr = 0;
2437        }
2438        dbgPrintf("lba: %i\n", *lbaPtr);
2439        break;
2440     }
2441        }
2442    
2443        free(line);
2444        fclose(grubConf);
2445        return 0;
2446    }
2447    
2448    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2449        FILE * grubConf;
2450        char * line = NULL;
2451        size_t res = 0, len = 0;
2452        char * lastParamPtr = NULL;
2453        char * secLastParamPtr = NULL;
2454        char installDeviceNumber = '\0';
2455        char * bounds = NULL;
2456    
2457        if (!path) return 1;
2458        if (!devicePtr) return 1;
2459    
2460        grubConf = fopen(path, "r");
2461        if (!grubConf) return 1;
2462    
2463        while ((res = getline(&line, &len, grubConf)) != -1) {
2464     if (strncmp(line, "setup", 5))
2465        continue;
2466    
2467     if (line[res - 1] == '\n')
2468        line[res - 1] = '\0';
2469     else if (len > res)
2470        line[res] = '\0';
2471     else {
2472        line = realloc(line, res + 1);
2473        line[res] = '\0';
2474     }
2475    
2476     lastParamPtr = bounds = line + res;
2477    
2478     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2479     while (!isspace(*lastParamPtr))
2480        lastParamPtr--;
2481     lastParamPtr++;
2482    
2483     secLastParamPtr = lastParamPtr - 2;
2484     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2485    
2486     if (lastParamPtr + 3 > bounds) {
2487        dbgPrintf("lastParamPtr going over boundary");
2488        fclose(grubConf);
2489        free(line);
2490        return 1;
2491     }
2492     if (!strncmp(lastParamPtr, "(hd", 3))
2493        lastParamPtr += 3;
2494     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2495    
2496     /*
2497     * Second last parameter will decide wether last parameter is
2498     * an IMAGE_DEVICE or INSTALL_DEVICE
2499     */
2500     while (!isspace(*secLastParamPtr))
2501        secLastParamPtr--;
2502     secLastParamPtr++;
2503    
2504     if (secLastParamPtr + 3 > bounds) {
2505        dbgPrintf("secLastParamPtr going over boundary");
2506        fclose(grubConf);
2507        free(line);
2508        return 1;
2509     }
2510     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2511     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2512        secLastParamPtr += 3;
2513        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2514        installDeviceNumber = *secLastParamPtr;
2515     } else {
2516        installDeviceNumber = *lastParamPtr;
2517     }
2518    
2519     *devicePtr = malloc(6);
2520     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2521     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2522     fclose(grubConf);
2523     free(line);
2524     return 0;
2525        }
2526    
2527        free(line);
2528        fclose(grubConf);
2529        return 1;
2530    }
2531    
2532    int grubGetBootFromDeviceMap(const char * device,
2533         char ** bootPtr) {
2534        FILE * deviceMap;
2535        char * line = NULL;
2536        size_t res = 0, len = 0;
2537        char * devicePtr;
2538        char * bounds = NULL;
2539        const char * path;
2540        const static char default_path[] = "/boot/grub/device.map";
2541    
2542        if (!device) return 1;
2543        if (!bootPtr) return 1;
2544    
2545        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2546     path = default_path;
2547    
2548        dbgPrintf("opening grub device.map file from: %s\n", path);
2549        deviceMap = fopen(path, "r");
2550        if (!deviceMap)
2551     return 1;
2552    
2553        while ((res = getline(&line, &len, deviceMap)) != -1) {
2554            if (!strncmp(line, "#", 1))
2555        continue;
2556    
2557     if (line[res - 1] == '\n')
2558        line[res - 1] = '\0';
2559     else if (len > res)
2560        line[res] = '\0';
2561     else {
2562        line = realloc(line, res + 1);
2563        line[res] = '\0';
2564     }
2565    
2566     devicePtr = line;
2567     bounds = line + res;
2568    
2569     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2570        devicePtr++;
2571     dbgPrintf("device: %s\n", devicePtr);
2572    
2573     if (!strncmp(devicePtr, device, strlen(device))) {
2574        devicePtr += strlen(device);
2575        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2576            devicePtr++;
2577    
2578        *bootPtr = strdup(devicePtr);
2579        break;
2580     }
2581        }
2582    
2583        free(line);
2584        fclose(deviceMap);
2585        return 0;
2586    }
2587    
2588    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2589        char * grubDevice;
2590    
2591        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2592     dbgPrintf("error looking for grub installation device\n");
2593        else
2594     dbgPrintf("grubby installation device: %s\n", grubDevice);
2595    
2596        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2597     dbgPrintf("error looking for grub boot device\n");
2598        else
2599     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2600    
2601        free(grubDevice);
2602        return 0;
2603    }
2604    
2605    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2606        /*
2607         * This SuSE grub configuration file at this location is not your average
2608         * grub configuration file, but instead the grub commands used to setup
2609         * grub on that system.
2610         */
2611        const char * path;
2612        const static char default_path[] = "/etc/grub.conf";
2613    
2614        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2615     path = default_path;
2616    
2617        if (!isSuseGrubConf(path)) return 1;
2618    
2619        if (lbaPtr) {
2620            *lbaPtr = 0;
2621            if (suseGrubConfGetLba(path, lbaPtr))
2622                return 1;
2623        }
2624    
2625        if (bootPtr) {
2626            *bootPtr = NULL;
2627            suseGrubConfGetBoot(path, bootPtr);
2628        }
2629    
2630        return 0;
2631    }
2632    
2633  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
2634      FILE * in;      FILE * in;
2635      char buf[1024];      char buf[1024];
# Line 2086  int parseSysconfigGrub(int * lbaPtr, cha Line 2678  int parseSysconfigGrub(int * lbaPtr, cha
2678  }  }
2679    
2680  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2681      char * boot;      char * boot = NULL;
2682      int lba;      int lba;
2683    
2684      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2685   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2686   if (boot) printf("boot=%s\n", boot);      free(boot);
2687        return;
2688     }
2689        } else {
2690            if (parseSysconfigGrub(&lba, &boot)) {
2691        free(boot);
2692        return;
2693     }
2694        }
2695    
2696        if (lba) printf("lba\n");
2697        if (boot) {
2698     printf("boot=%s\n", boot);
2699     free(boot);
2700      }      }
2701  }  }
2702    
# Line 2140  struct singleLine * addLineTmpl(struct s Line 2745  struct singleLine * addLineTmpl(struct s
2745  {  {
2746      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2747    
2748        if (isEfi && cfi == &grub2ConfigType) {
2749     enum lineType_e old = newLine->type;
2750     newLine->type = preferredLineType(newLine->type, cfi);
2751     if (old != newLine->type)
2752        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2753        }
2754    
2755      if (val) {      if (val) {
2756   /* override the inherited value with our own.   /* override the inherited value with our own.
2757   * This is a little weak because it only applies to elements[1]   * This is a little weak because it only applies to elements[1]
# Line 2149  struct singleLine * addLineTmpl(struct s Line 2761  struct singleLine * addLineTmpl(struct s
2761   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2762    
2763   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2764   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)) {
2765      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2766      if (rootspec != NULL) {      if (rootspec != NULL) {
2767   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 2186  struct singleLine *  addLine(struct sing Line 2798  struct singleLine *  addLine(struct sing
2798      /* 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
2799       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2800       */       */
   
2801      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2802   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2803   tmpl.type = type;   tmpl.type = type;
# Line 2520  int updateActualImage(struct grubConfig Line 3131  int updateActualImage(struct grubConfig
3131      firstElement = 2;      firstElement = 2;
3132    
3133   } else {   } else {
3134      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3135      if (!line) {      if (!line) {
3136   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3137   continue;   continue;
# Line 2676  int updateImage(struct grubConfig * cfg, Line 3287  int updateImage(struct grubConfig * cfg,
3287      return rc;      return rc;
3288  }  }
3289    
3290    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3291     const char * image, const char * prefix, const char * initrd) {
3292        struct singleEntry * entry;
3293        struct singleLine * line, * kernelLine, *endLine = NULL;
3294        int index = 0;
3295    
3296        if (!image) return 0;
3297    
3298        for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) {
3299            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3300            if (!kernelLine) continue;
3301    
3302            if (prefix) {
3303                int prefixLen = strlen(prefix);
3304                if (!strncmp(initrd, prefix, prefixLen))
3305                    initrd += prefixLen;
3306            }
3307     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3308     if (endLine)
3309        removeLine(entry, endLine);
3310            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3311     kernelLine->indent, initrd);
3312            if (!line)
3313        return 1;
3314     if (endLine) {
3315        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3316                if (!line)
3317     return 1;
3318     }
3319    
3320            break;
3321        }
3322    
3323        return 0;
3324    }
3325    
3326  int updateInitrd(struct grubConfig * cfg, const char * image,  int updateInitrd(struct grubConfig * cfg, const char * image,
3327                   const char * prefix, const char * initrd) {                   const char * prefix, const char * initrd) {
3328      struct singleEntry * entry;      struct singleEntry * entry;
# Line 2685  int updateInitrd(struct grubConfig * cfg Line 3332  int updateInitrd(struct grubConfig * cfg
3332      if (!image) return 0;      if (!image) return 0;
3333    
3334      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3335          kernelLine = getLineByType(LT_KERNEL, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3336          if (!kernelLine) continue;          if (!kernelLine) continue;
3337    
3338          line = getLineByType(LT_INITRD, entry->lines);          line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3339          if (line)          if (line)
3340              removeLine(entry, line);              removeLine(entry, line);
3341          if (prefix) {          if (prefix) {
# Line 2699  int updateInitrd(struct grubConfig * cfg Line 3346  int updateInitrd(struct grubConfig * cfg
3346   endLine = getLineByType(LT_ENTRY_END, entry->lines);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3347   if (endLine)   if (endLine)
3348      removeLine(entry, endLine);      removeLine(entry, endLine);
3349          line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);   enum lineType_e lt;
3350     switch(kernelLine->type) {
3351        case LT_KERNEL:
3352            lt = LT_INITRD;
3353     break;
3354        case LT_KERNEL_EFI:
3355            lt = LT_INITRD_EFI;
3356     break;
3357        case LT_KERNEL_16:
3358            lt = LT_INITRD_16;
3359     break;
3360        default:
3361            lt = preferredLineType(LT_INITRD, cfg->cfi);
3362     }
3363            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3364          if (!line)          if (!line)
3365      return 1;      return 1;
3366   if (endLine) {   if (endLine) {
# Line 2905  int checkForGrub(struct grubConfig * con Line 3566  int checkForGrub(struct grubConfig * con
3566      int fd;      int fd;
3567      unsigned char bootSect[512];      unsigned char bootSect[512];
3568      char * boot;      char * boot;
3569        int onSuse = isSuseSystem();
3570    
3571      if (parseSysconfigGrub(NULL, &boot))  
3572   return 0;      if (onSuse) {
3573     if (parseSuseGrubConf(NULL, &boot))
3574        return 0;
3575        } else {
3576     if (parseSysconfigGrub(NULL, &boot))
3577        return 0;
3578        }
3579    
3580      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3581      if (!boot)      if (!boot)
# Line 2926  int checkForGrub(struct grubConfig * con Line 3594  int checkForGrub(struct grubConfig * con
3594      }      }
3595      close(fd);      close(fd);
3596    
3597        /* The more elaborate checks do not work on SuSE. The checks done
3598         * seem to be reasonble (at least for now), so just return success
3599         */
3600        if (onSuse)
3601     return 2;
3602    
3603      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3604  }  }
3605    
# Line 2959  int checkForExtLinux(struct grubConfig * Line 3633  int checkForExtLinux(struct grubConfig *
3633      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3634  }  }
3635    
3636    int checkForYaboot(struct grubConfig * config) {
3637        /*
3638         * This is a simplistic check that we consider good enough for own puporses
3639         *
3640         * If we were to properly check if yaboot is *installed* we'd need to:
3641         * 1) get the system boot device (LT_BOOT)
3642         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3643         *    the content on the boot device
3644         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3645         * 4) check again if binary and boot device contents match
3646         */
3647        if (!access("/etc/yaboot.conf", R_OK))
3648     return 2;
3649    
3650        return 1;
3651    }
3652    
3653    int checkForElilo(struct grubConfig * config) {
3654        if (!access("/etc/elilo.conf", R_OK))
3655     return 2;
3656    
3657        return 1;
3658    }
3659    
3660  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3661      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3662    
# Line 3021  int addNewKernel(struct grubConfig * con Line 3719  int addNewKernel(struct grubConfig * con
3719   const char * newKernelPath, const char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3720   const char * newKernelArgs, const char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3721   const char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3722                   const char * newMBKernel, const char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3723     const char * newDevTreePath) {
3724      struct singleEntry * new;      struct singleEntry * new;
3725      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3726      int needs;      int needs;
# Line 3062  int addNewKernel(struct grubConfig * con Line 3761  int addNewKernel(struct grubConfig * con
3761          needs |= NEED_MB;          needs |= NEED_MB;
3762          new->multiboot = 1;          new->multiboot = 1;
3763      }      }
3764        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3765     needs |= NEED_DEVTREE;
3766    
3767      if (template) {      if (template) {
3768   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 3075  int addNewKernel(struct grubConfig * con Line 3776  int addNewKernel(struct grubConfig * con
3776      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3777      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3778    
3779      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
     tmplLine->numElements >= 2) {  
3780   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3781      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3782       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 3153  int addNewKernel(struct grubConfig * con Line 3853  int addNewKernel(struct grubConfig * con
3853      /* template is multi but new is not,      /* template is multi but new is not,
3854       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3855       */       */
3856      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3857      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3858      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3859   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3860     config->cfi)->key);
3861      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3862    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3863      config->cfi);
3864      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3865   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3866      char *initrdVal;      char *initrdVal;
3867      /* template is multi but new is not,      /* template is multi but new is not,
3868       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3869       */       */
3870      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3871      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3872      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3873   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3874     config->cfi)->key);
3875      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3876      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3877      free(initrdVal);      free(initrdVal);
3878      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3879   }   }
3880    
3881      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3882   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3883      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3884      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 3230  int addNewKernel(struct grubConfig * con Line 3932  int addNewKernel(struct grubConfig * con
3932      static const char *prefix = "'Loading ";      static const char *prefix = "'Loading ";
3933      if (tmplLine->numElements > 1 &&      if (tmplLine->numElements > 1 &&
3934      strstr(tmplLine->elements[1].item, prefix) &&      strstr(tmplLine->elements[1].item, prefix) &&
3935      masterLine->next && masterLine->next->type == LT_KERNEL) {      masterLine->next &&
3936        iskernel(masterLine->next->type)) {
3937   char *newTitle = malloc(strlen(prefix) +   char *newTitle = malloc(strlen(prefix) +
3938   strlen(newKernelTitle) + 2);   strlen(newKernelTitle) + 2);
3939    
# Line 3245  int addNewKernel(struct grubConfig * con Line 3948  int addNewKernel(struct grubConfig * con
3948   newLine = addLineTmpl(new, tmplLine, newLine, NULL,   newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3949   config->cfi);   config->cfi);
3950      }      }
3951        } else if (tmplLine->type == LT_DEVTREE &&
3952           tmplLine->numElements == 2 && newDevTreePath) {
3953            newLine = addLineTmpl(new, tmplLine, newLine,
3954          newDevTreePath + strlen(prefix),
3955          config->cfi);
3956     needs &= ~NEED_DEVTREE;
3957        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
3958     const char *ndtp = newDevTreePath;
3959     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
3960        ndtp += strlen(prefix);
3961     newLine = addLine(new, config->cfi, LT_DEVTREE,
3962      config->secondaryIndent,
3963      ndtp);
3964     needs &= ~NEED_DEVTREE;
3965     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3966      } else {      } else {
3967   /* pass through other lines from the template */   /* pass through other lines from the template */
3968   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 3257  int addNewKernel(struct grubConfig * con Line 3975  int addNewKernel(struct grubConfig * con
3975   */   */
3976   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
3977      case LT_KERNEL:      case LT_KERNEL:
3978        case LT_KERNEL_EFI:
3979        case LT_KERNEL_16:
3980   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
3981      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
3982   } else {   } else {
3983      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
3984              preferredLineType(LT_KERNEL, config->cfi),
3985        config->primaryIndent,        config->primaryIndent,
3986        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
3987      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 3336  int addNewKernel(struct grubConfig * con Line 4057  int addNewKernel(struct grubConfig * con
4057      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
4058   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4059    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4060        config->cfi)) ?        config->cfi))
4061    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
4062     : preferredLineType(LT_KERNEL, config->cfi),
4063    config->secondaryIndent,    config->secondaryIndent,
4064    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
4065   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 3353  int addNewKernel(struct grubConfig * con Line 4075  int addNewKernel(struct grubConfig * con
4075   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4076   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4077    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4078        config->cfi)) ?        config->cfi))
4079    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
4080       : preferredLineType(LT_INITRD, config->cfi),
4081    config->secondaryIndent,    config->secondaryIndent,
4082    initrdVal);    initrdVal);
4083   free(initrdVal);   free(initrdVal);
4084   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4085      }      }
4086        if (needs & NEED_DEVTREE) {
4087     newLine = addLine(new, config->cfi, LT_DEVTREE,
4088      config->secondaryIndent,
4089      newDevTreePath);
4090     needs &= ~NEED_DEVTREE;
4091        }
4092    
4093        /* NEEDS_END must be last on bootloaders that need it... */
4094      if (needs & NEED_END) {      if (needs & NEED_END) {
4095   newLine = addLine(new, config->cfi, LT_ENTRY_END,   newLine = addLine(new, config->cfi, LT_ENTRY_END,
4096   config->secondaryIndent, NULL);   config->secondaryIndent, NULL);
4097   needs &= ~NEED_END;   needs &= ~NEED_END;
4098      }      }
   
4099      if (needs) {      if (needs) {
4100   printf(_("grubby: needs=%d, aborting\n"), needs);   printf(_("grubby: needs=%d, aborting\n"), needs);
4101   abort();   abort();
# Line 3386  static void traceback(int signum) Line 4116  static void traceback(int signum)
4116      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
4117      size = backtrace(array, 40);      size = backtrace(array, 40);
4118    
4119      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4120              (unsigned long)size);              (unsigned long)size);
4121      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
4122      exit(1);      exit(1);
# Line 3411  int main(int argc, const char ** argv) { Line 4141  int main(int argc, const char ** argv) {
4141      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4142      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4143      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4144      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4145      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4146      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4147      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 3421  int main(int argc, const char ** argv) { Line 4151  int main(int argc, const char ** argv) {
4151      char * removeArgs = NULL;      char * removeArgs = NULL;
4152      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4153      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4154        char * envPath = NULL;
4155      const char * chptr = NULL;      const char * chptr = NULL;
4156      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4157      struct grubConfig * config;      struct grubConfig * config;
# Line 3429  int main(int argc, const char ** argv) { Line 4160  int main(int argc, const char ** argv) {
4160      int displayDefault = 0;      int displayDefault = 0;
4161      int displayDefaultIndex = 0;      int displayDefaultIndex = 0;
4162      int displayDefaultTitle = 0;      int displayDefaultTitle = 0;
4163        int defaultIndex = -1;
4164      struct poptOption options[] = {      struct poptOption options[] = {
4165   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4166      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 3446  int main(int argc, const char ** argv) { Line 4178  int main(int argc, const char ** argv) {
4178   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4179      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4180      _("bootfs") },      _("bootfs") },
4181  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4182   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4183      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4184  #endif  #endif
4185   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4186      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 3467  int main(int argc, const char ** argv) { Line 4199  int main(int argc, const char ** argv) {
4199      _("display the index of the default kernel") },      _("display the index of the default kernel") },
4200   { "default-title", 0, 0, &displayDefaultTitle, 0,   { "default-title", 0, 0, &displayDefaultTitle, 0,
4201      _("display the title of the default kernel") },      _("display the title of the default kernel") },
4202     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4203        _("device tree file for new stanza"), _("dtb-path") },
4204   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4205      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4206     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4207        _("force grub2 stanzas to use efi") },
4208     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4209        _("path for environment data"),
4210        _("path") },
4211   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4212      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4213   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
# Line 3481  int main(int argc, const char ** argv) { Line 4220  int main(int argc, const char ** argv) {
4220   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4221      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4222   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4223      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4224   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4225      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4226   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 3501  int main(int argc, const char ** argv) { Line 4240  int main(int argc, const char ** argv) {
4240   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4241      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4242        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4243     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4244        _("make the given entry index the default entry"),
4245        _("entry-index") },
4246   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4247      _("configure silo bootloader") },      _("configure silo bootloader") },
4248   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 3522  int main(int argc, const char ** argv) { Line 4264  int main(int argc, const char ** argv) {
4264    
4265      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4266    
4267        int i = 0;
4268        for (int j = 1; j < argc; j++)
4269     i += strlen(argv[j]) + 1;
4270        saved_command_line = malloc(i);
4271        if (!saved_command_line) {
4272     fprintf(stderr, "grubby: %m\n");
4273     exit(1);
4274        }
4275        saved_command_line[0] = '\0';
4276        for (int j = 1; j < argc; j++) {
4277     strcat(saved_command_line, argv[j]);
4278     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4279        }
4280    
4281      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4282      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4283    
# Line 3565  int main(int argc, const char ** argv) { Line 4321  int main(int argc, const char ** argv) {
4321   return 1;   return 1;
4322      } else if (configureGrub2) {      } else if (configureGrub2) {
4323   cfi = &grub2ConfigType;   cfi = &grub2ConfigType;
4324     if (envPath)
4325        cfi->envFile = envPath;
4326      } else if (configureLilo) {      } else if (configureLilo) {
4327   cfi = &liloConfigType;   cfi = &liloConfigType;
4328      } else if (configureGrub) {      } else if (configureGrub) {
# Line 3608  int main(int argc, const char ** argv) { Line 4366  int main(int argc, const char ** argv) {
4366      grubConfig = cfi->defaultConfig;      grubConfig = cfi->defaultConfig;
4367      }      }
4368    
4369      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4370    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4371    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4372        (defaultIndex >= 0))) {
4373   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4374    "specified option"));    "specified option"));
4375   return 1;   return 1;
4376      }      }
4377    
4378      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4379     removeKernelPath)) {     removeKernelPath)) {
4380   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4381    "be used when adding or removing kernels\n"));    "be used when adding or removing kernels\n"));
# Line 3652  int main(int argc, const char ** argv) { Line 4411  int main(int argc, const char ** argv) {
4411   makeDefault = 1;   makeDefault = 1;
4412   defaultKernel = NULL;   defaultKernel = NULL;
4413      }      }
4414        else if (defaultKernel && (defaultIndex >= 0)) {
4415     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4416      "may not be used together\n"));
4417     return 1;
4418        }
4419    
4420      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4421   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
# Line 3660  int main(int argc, const char ** argv) { Line 4424  int main(int argc, const char ** argv) {
4424      }      }
4425    
4426      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4427   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4428          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4429     && (defaultIndex == -1)) {
4430   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4431   return 1;   return 1;
4432      }      }
# Line 3688  int main(int argc, const char ** argv) { Line 4453  int main(int argc, const char ** argv) {
4453      }      }
4454    
4455      if (bootloaderProbe) {      if (bootloaderProbe) {
4456   int lrc = 0, grc = 0, gr2c = 0, erc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4457   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4458    
4459   const char *grub2config = grub2FindConfig(&grub2ConfigType);   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4460   if (grub2config) {   if (grub2config) {
# Line 3717  int main(int argc, const char ** argv) { Line 4482  int main(int argc, const char ** argv) {
4482   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4483   }   }
4484    
4485     if (!access(eliloConfigType.defaultConfig, F_OK)) {
4486        econfig = readConfig(eliloConfigType.defaultConfig,
4487     &eliloConfigType);
4488        if (!econfig)
4489     erc = 1;
4490        else
4491     erc = checkForElilo(econfig);
4492     }
4493    
4494   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4495      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4496      if (!lconfig)      if (!lconfig)
4497   erc = 1;   extrc = 1;
4498      else      else
4499   erc = checkForExtLinux(lconfig);   extrc = checkForExtLinux(lconfig);
4500   }   }
4501    
4502   if (lrc == 1 || grc == 1 || gr2c == 1) return 1;  
4503     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4504        yconfig = readConfig(yabootConfigType.defaultConfig,
4505     &yabootConfigType);
4506        if (!yconfig)
4507     yrc = 1;
4508        else
4509     yrc = checkForYaboot(yconfig);
4510     }
4511    
4512     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4513     erc == 1)
4514        return 1;
4515    
4516   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4517   if (gr2c == 2) printf("grub2\n");   if (gr2c == 2) printf("grub2\n");
4518   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4519   if (erc == 2) printf("extlinux\n");   if (extrc == 2) printf("extlinux\n");
4520     if (yrc == 2) printf("yaboot\n");
4521     if (erc == 2) printf("elilo\n");
4522    
4523   return 0;   return 0;
4524      }      }
4525    
4526        if (grubConfig == NULL) {
4527     printf("Could not find bootloader configuration file.\n");
4528     exit(1);
4529        }
4530    
4531      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4532      if (!config) return 1;      if (!config) return 1;
4533    
# Line 3744  int main(int argc, const char ** argv) { Line 4537  int main(int argc, const char ** argv) {
4537          char * rootspec;          char * rootspec;
4538    
4539   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4540     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4541     cfi->defaultIsSaved)
4542        config->defaultImage = 0;
4543   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4544   if (!entry) return 0;   if (!entry) return 0;
4545   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4546    
4547   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
4548   if (!line) return 0;   if (!line) return 0;
4549    
4550          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 3762  int main(int argc, const char ** argv) { Line 4558  int main(int argc, const char ** argv) {
4558   struct singleEntry * entry;   struct singleEntry * entry;
4559    
4560   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4561     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4562     cfi->defaultIsSaved)
4563        config->defaultImage = 0;
4564   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4565   if (!entry) return 0;   if (!entry) return 0;
4566    
# Line 3784  int main(int argc, const char ** argv) { Line 4583  int main(int argc, const char ** argv) {
4583    
4584      } else if (displayDefaultIndex) {      } else if (displayDefaultIndex) {
4585          if (config->defaultImage == -1) return 0;          if (config->defaultImage == -1) return 0;
4586     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4587     cfi->defaultIsSaved)
4588        config->defaultImage = 0;
4589          printf("%i\n", config->defaultImage);          printf("%i\n", config->defaultImage);
4590            return 0;
4591    
4592      } else if (kernelInfo)      } else if (kernelInfo)
4593   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
# Line 3797  int main(int argc, const char ** argv) { Line 4600  int main(int argc, const char ** argv) {
4600      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4601      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4602      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4603      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4604      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4605      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4606                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4607      if (updateKernelPath && newKernelInitrd) {      if (updateKernelPath && newKernelInitrd) {
4608              if (updateInitrd(config, updateKernelPath, bootPrefix,      if (newMBKernel) {
4609                               newKernelInitrd)) return 1;      if (addMBInitrd(config, newMBKernel, updateKernelPath,
4610     bootPrefix, newKernelInitrd))
4611        return 1;
4612        } else {
4613        if (updateInitrd(config, updateKernelPath, bootPrefix,
4614     newKernelInitrd))
4615     return 1;
4616        }
4617      }      }
4618      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4619                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4620                       (const char **)extraInitrds, extraInitrdCount,                       (const char **)extraInitrds, extraInitrdCount,
4621                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4622            
4623    
4624      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {

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