Magellan Linux

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

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

trunk/grubby/grubby.c revision 1800 by niro, Mon Apr 16 17:46:40 2012 UTC tags/grubby-8_37/grubby.c revision 2976 by niro, Thu Jun 30 10:23:26 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 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) {
   int i;  
386    int count = 0;    int count = 0;
387    
388    for (i = 0; i < line->numElements; i++) {    for (int i = 0; i < line->numElements; i++) {
389      int indentSize = 0;      int indentSize = 0;
390    
391      count = count + strlen(line->elements[i].item);      count = count + strlen(line->elements[i].item);
# Line 272  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 329  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 433  struct keywordTypes extlinuxKeywords[] = Line 582  struct keywordTypes extlinuxKeywords[] =
582      { "initrd",    LT_INITRD,      ' ', ',' },      { "initrd",    LT_INITRD,      ' ', ',' },
583      { "append",    LT_KERNELARGS,  ' ' },      { "append",    LT_KERNELARGS,  ' ' },
584      { "prompt",     LT_UNKNOWN,     ' ' },      { "prompt",     LT_UNKNOWN,     ' ' },
585        { "fdt",        LT_DEVTREE,     ' ' },
586        { "fdtdir",     LT_DEVTREE,     ' ' },
587      { NULL,    0, 0 },      { NULL,    0, 0 },
588  };  };
589  int useextlinuxmenu;  int useextlinuxmenu;
# Line 483  struct configFileInfo ziplConfigType = { Line 634  struct configFileInfo ziplConfigType = {
634  struct configFileInfo extlinuxConfigType = {  struct configFileInfo extlinuxConfigType = {
635      .defaultConfig = "/boot/extlinux/extlinux.conf",      .defaultConfig = "/boot/extlinux/extlinux.conf",
636      .keywords = extlinuxKeywords,      .keywords = extlinuxKeywords,
637        .caseInsensitive = 1,
638      .entryStart = LT_TITLE,      .entryStart = LT_TITLE,
639      .needsBootPrefix = 1,      .needsBootPrefix = 1,
640      .maxTitleLength = 255,      .maxTitleLength = 255,
641      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
642        .defaultIsUnquoted = 1,
643  };  };
644    
645  struct grubConfig {  struct grubConfig {
# Line 507  struct singleEntry * findEntryByIndex(st Line 660  struct singleEntry * findEntryByIndex(st
660  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
661       const char * path, const char * prefix,       const char * path, const char * prefix,
662       int * index);       int * index);
663    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
664          int * index);
665  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
666  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
667  struct singleLine * lineDup(struct singleLine * line);  struct singleLine * lineDup(struct singleLine * line);
# Line 571  static char * sdupprintf(const char *for Line 726  static char * sdupprintf(const char *for
726      return buf;      return buf;
727  }  }
728    
729    static enum lineType_e preferredLineType(enum lineType_e type,
730     struct configFileInfo *cfi) {
731        if (isEfi && cfi == &grub2ConfigType) {
732     switch (type) {
733     case LT_KERNEL:
734        return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
735     case LT_INITRD:
736        return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
737     default:
738        return type;
739     }
740    #if defined(__i386__) || defined(__x86_64__)
741        } else if (cfi == &grub2ConfigType) {
742     switch (type) {
743     case LT_KERNEL:
744        return LT_KERNEL_16;
745     case LT_INITRD:
746        return LT_INITRD_16;
747     default:
748        return type;
749     }
750    #endif
751        }
752        return type;
753    }
754    
755  static struct keywordTypes * getKeywordByType(enum lineType_e type,  static struct keywordTypes * getKeywordByType(enum lineType_e type,
756        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
757      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
     for (kw = cfi->keywords; kw->key; kw++) {  
758   if (kw->type == type)   if (kw->type == type)
759      return kw;      return kw;
760      }      }
# Line 604  static char * getuuidbydev(char *device) Line 784  static char * getuuidbydev(char *device)
784    
785  static enum lineType_e getTypeByKeyword(char * keyword,  static enum lineType_e getTypeByKeyword(char * keyword,
786   struct configFileInfo * cfi) {   struct configFileInfo * cfi) {
787      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
788      for (kw = cfi->keywords; kw->key; kw++) {   if (cfi->caseInsensitive) {
789   if (!strcmp(keyword, kw->key))      if (!strcasecmp(keyword, kw->key))
790      return kw->type;                  return kw->type;
791     } else {
792        if (!strcmp(keyword, kw->key))
793            return kw->type;
794     }
795      }      }
796      return LT_UNKNOWN;      return LT_UNKNOWN;
797  }  }
# Line 646  static int isEntryStart(struct singleLin Line 830  static int isEntryStart(struct singleLin
830  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
831  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
832      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
833      char * title;      char * title = NULL;
834      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
835      title++;   title = strdup(line->elements[0].item);
836      *(title + strlen(title) - 1) = '\0';   title++;
837     *(title + strlen(title) - 1) = '\0';
838        } else if (line->type == LT_MENUENTRY)
839     title = strdup(line->elements[1].item);
840        else
841     return NULL;
842      return title;      return title;
843  }  }
844    
# Line 692  static void lineInit(struct singleLine * Line 881  static void lineInit(struct singleLine *
881  }  }
882    
883  struct singleLine * lineDup(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
     int i;  
884      struct singleLine * newLine = malloc(sizeof(*newLine));      struct singleLine * newLine = malloc(sizeof(*newLine));
885    
886      newLine->indent = strdup(line->indent);      newLine->indent = strdup(line->indent);
# Line 702  struct singleLine * lineDup(struct singl Line 890  struct singleLine * lineDup(struct singl
890      newLine->elements = malloc(sizeof(*newLine->elements) *      newLine->elements = malloc(sizeof(*newLine->elements) *
891         newLine->numElements);         newLine->numElements);
892    
893      for (i = 0; i < newLine->numElements; i++) {      for (int i = 0; i < newLine->numElements; i++) {
894   newLine->elements[i].indent = strdup(line->elements[i].indent);   newLine->elements[i].indent = strdup(line->elements[i].indent);
895   newLine->elements[i].item = strdup(line->elements[i].item);   newLine->elements[i].item = strdup(line->elements[i].item);
896      }      }
# Line 711  struct singleLine * lineDup(struct singl Line 899  struct singleLine * lineDup(struct singl
899  }  }
900    
901  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
     int i;  
   
902      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
903    
904      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
905   free(line->elements[i].item);   free(line->elements[i].item);
906   free(line->elements[i].indent);   free(line->elements[i].indent);
907      }      }
# Line 726  static void lineFree(struct singleLine * Line 912  static void lineFree(struct singleLine *
912    
913  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
914       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
915      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
916    
917      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
918     /* Need to handle this, because we strip the quotes from
919     * menuentry when read it. */
920     if (line->type == LT_MENUENTRY && i == 1) {
921        if(!isquote(*line->elements[i].item))
922     fprintf(out, "\'%s\'", line->elements[i].item);
923        else
924     fprintf(out, "%s", line->elements[i].item);
925        fprintf(out, "%s", line->elements[i].indent);
926    
927        continue;
928     }
929    
930   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
931      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
932    
# Line 824  static int getNextLine(char ** bufPtr, s Line 1020  static int getNextLine(char ** bufPtr, s
1020      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
1021   char * fullLine;   char * fullLine;
1022   int len;   int len;
  int i;  
1023    
1024   len = strlen(line->indent);   len = strlen(line->indent);
1025   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
1026      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
1027     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1028    
# Line 836  static int getNextLine(char ** bufPtr, s Line 1031  static int getNextLine(char ** bufPtr, s
1031   free(line->indent);   free(line->indent);
1032   line->indent = fullLine;   line->indent = fullLine;
1033    
1034   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1035      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1036      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1037      free(line->elements[i].item);      free(line->elements[i].item);
# Line 855  static int getNextLine(char ** bufPtr, s Line 1050  static int getNextLine(char ** bufPtr, s
1050   * elements up more   * elements up more
1051   */   */
1052   if (!isspace(kw->separatorChar)) {   if (!isspace(kw->separatorChar)) {
     int i;  
1053      char indent[2] = "";      char indent[2] = "";
1054      indent[0] = kw->separatorChar;      indent[0] = kw->separatorChar;
1055      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1056   char *p;   char *p;
  int j;  
1057   int numNewElements;   int numNewElements;
1058    
1059   numNewElements = 0;   numNewElements = 0;
# Line 876  static int getNextLine(char ** bufPtr, s Line 1069  static int getNextLine(char ** bufPtr, s
1069      sizeof(*line->elements) * elementsAlloced);      sizeof(*line->elements) * elementsAlloced);
1070   }   }
1071    
1072   for (j = line->numElements; j > i; j--) {   for (int j = line->numElements; j > i; j--) {
1073   line->elements[j + numNewElements] = line->elements[j];   line->elements[j + numNewElements] = line->elements[j];
1074   }   }
1075   line->numElements += numNewElements;   line->numElements += numNewElements;
# Line 889  static int getNextLine(char ** bufPtr, s Line 1082  static int getNextLine(char ** bufPtr, s
1082   break;   break;
1083   }   }
1084    
1085   free(line->elements[i].indent);   line->elements[i + 1].indent = line->elements[i].indent;
1086   line->elements[i].indent = strdup(indent);   line->elements[i].indent = strdup(indent);
1087   *p++ = '\0';   *p++ = '\0';
1088   i++;   i++;
1089   line->elements[i].item = strdup(p);   line->elements[i].item = strdup(p);
  line->elements[i].indent = strdup("");  
  p = line->elements[i].item;  
1090   }   }
1091      }      }
1092   }   }
# Line 905  static int getNextLine(char ** bufPtr, s Line 1096  static int getNextLine(char ** bufPtr, s
1096      return 0;      return 0;
1097  }  }
1098    
1099    static int isnumber(const char *s)
1100    {
1101        int i;
1102        for (i = 0; s[i] != '\0'; i++)
1103     if (s[i] < '0' || s[i] > '9')
1104        return 0;
1105        return i;
1106    }
1107    
1108  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1109        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1110      int in;      int in;
# Line 916  static struct grubConfig * readConfig(co Line 1116  static struct grubConfig * readConfig(co
1116      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1117      char * end;      char * end;
1118      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1119      int i, len;      int len;
1120      char * buf;      char * buf;
1121    
1122      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1123            printf("Could not find bootloader configuration\n");
1124            exit(1);
1125        } else if (!strcmp(inName, "-")) {
1126   in = 0;   in = 0;
1127      } else {      } else {
1128   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 979  static struct grubConfig * readConfig(co Line 1182  static struct grubConfig * readConfig(co
1182   }   }
1183    
1184   if (line->type == LT_SET_VARIABLE) {   if (line->type == LT_SET_VARIABLE) {
     int i;  
1185      dbgPrintf("found 'set' command (%d elements): ", line->numElements);      dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1186      dbgPrintf("%s", line->indent);      dbgPrintf("%s", line->indent);
1187      for (i = 0; i < line->numElements; i++)      for (int i = 0; i < line->numElements; i++)
1188   dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);   dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1189      dbgPrintf("\n");      dbgPrintf("\n");
1190      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1191      if (kwType && line->numElements == 3 &&      if (kwType && line->numElements == 3 &&
1192      !strcmp(line->elements[1].item, kwType->key)) {      !strcmp(line->elements[1].item, kwType->key) &&
1193        !is_special_grub2_variable(line->elements[2].item)) {
1194   dbgPrintf("Line sets default config\n");   dbgPrintf("Line sets default config\n");
1195   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1196   defaultLine = line;   defaultLine = line;
1197      }      }
  } else if (line->type == LT_DEFAULT && line->numElements == 2) {  
     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;  
     defaultLine = line;  
1198    
1199          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1200      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1201       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1202       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1203       */       */
1204      if (entry->multiboot)      if (entry && entry->multiboot)
1205   line->type = LT_HYPER;   line->type = LT_HYPER;
1206    
1207          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 1010  static struct grubConfig * readConfig(co Line 1210  static struct grubConfig * readConfig(co
1210       * This only applies to grub, but that's the only place we       * This only applies to grub, but that's the only place we
1211       * should find LT_MBMODULE lines anyway.       * should find LT_MBMODULE lines anyway.
1212       */       */
1213      struct singleLine * l;      for (struct singleLine *l = entry->lines; l; l = l->next) {
     for (l = entry->lines; l; l = l->next) {  
1214   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1215      break;      break;
1216   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1217      l->type = LT_HYPER;      l->type = LT_HYPER;
1218      break;      break;
1219   }   }
# Line 1028  static struct grubConfig * readConfig(co Line 1227  static struct grubConfig * readConfig(co
1227      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1228      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1229    
1230   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1231      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1232        /* make the title/default a single argument (undoing our parsing) */
1233      len = 0;      len = 0;
1234      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1235   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1236   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1237      }      }
1238      buf = malloc(len + 1);      buf = malloc(len + 1);
1239      *buf = '\0';      *buf = '\0';
1240    
1241      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1242   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1243   free(line->elements[i].item);   free(line->elements[i].item);
1244    
# Line 1052  static struct grubConfig * readConfig(co Line 1252  static struct grubConfig * readConfig(co
1252      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1253      line->elements[1].item = buf;      line->elements[1].item = buf;
1254      line->numElements = 2;      line->numElements = 2;
1255     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1256        /* let --remove-kernel="TITLE=what" work */
1257        len = 0;
1258        char *extras;
1259        char *title;
1260    
1261        for (int i = 1; i < line->numElements; i++) {
1262     len += strlen(line->elements[i].item);
1263     len += strlen(line->elements[i].indent);
1264        }
1265        buf = malloc(len + 1);
1266        *buf = '\0';
1267    
1268        /* allocate mem for extra flags. */
1269        extras = malloc(len + 1);
1270        *extras = '\0';
1271    
1272        /* get title. */
1273        for (int i = 0; i < line->numElements; i++) {
1274     if (!strcmp(line->elements[i].item, "menuentry"))
1275        continue;
1276     if (isquote(*line->elements[i].item))
1277        title = line->elements[i].item + 1;
1278     else
1279        title = line->elements[i].item;
1280    
1281     len = strlen(title);
1282            if (isquote(title[len-1])) {
1283        strncat(buf, title,len-1);
1284        break;
1285     } else {
1286        strcat(buf, title);
1287        strcat(buf, line->elements[i].indent);
1288     }
1289        }
1290    
1291        /* get extras */
1292        int count = 0;
1293        for (int i = 0; i < line->numElements; i++) {
1294     if (count >= 2) {
1295        strcat(extras, line->elements[i].item);
1296        strcat(extras, line->elements[i].indent);
1297     }
1298    
1299     if (!strcmp(line->elements[i].item, "menuentry"))
1300        continue;
1301    
1302     /* count ' or ", there should be two in menuentry line. */
1303     if (isquote(*line->elements[i].item))
1304        count++;
1305    
1306     len = strlen(line->elements[i].item);
1307    
1308     if (isquote(line->elements[i].item[len -1]))
1309        count++;
1310    
1311     /* ok, we get the final ' or ", others are extras. */
1312                }
1313        line->elements[1].indent =
1314     line->elements[line->numElements - 2].indent;
1315        line->elements[1].item = buf;
1316        line->elements[2].indent =
1317     line->elements[line->numElements - 2].indent;
1318        line->elements[2].item = extras;
1319        line->numElements = 3;
1320   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1321      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1322         on write. This is one of the few (the only?) places that grubby         on write. This is one of the few (the only?) places that grubby
# Line 1061  static struct grubConfig * readConfig(co Line 1325  static struct grubConfig * readConfig(co
1325      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1326   int last, len;   int last, len;
1327    
1328   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1329      memmove(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1330      strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1331    
1332   last = line->numElements - 1;   last = line->numElements - 1;
1333   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1334   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1335      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1336      }      }
1337   }   }
1338    
1339     if (line->type == LT_DEFAULT && line->numElements == 2) {
1340        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1341        defaultLine = line;
1342     }
1343    
1344   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1345     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1346     probably responsible for putting new images in the wrong     probably responsible for putting new images in the wrong
# Line 1129  static struct grubConfig * readConfig(co Line 1398  static struct grubConfig * readConfig(co
1398          if (defaultLine->numElements > 2 &&          if (defaultLine->numElements > 2 &&
1399      cfi->defaultSupportSaved &&      cfi->defaultSupportSaved &&
1400      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1401      cfg->defaultImage = DEFAULT_SAVED_GRUB2;   cfg->cfi->defaultIsSaved = 1;
1402     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1403     if (cfg->cfi->getEnv) {
1404        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1405        if (defTitle) {
1406     int index = 0;
1407     if (isnumber(defTitle)) {
1408        index = atoi(defTitle);
1409        entry = findEntryByIndex(cfg, index);
1410     } else {
1411        entry = findEntryByTitle(cfg, defTitle, &index);
1412     }
1413     if (entry)
1414        cfg->defaultImage = index;
1415        }
1416     }
1417   } else if (cfi->defaultIsVariable) {   } else if (cfi->defaultIsVariable) {
1418      char *value = defaultLine->elements[2].item;      char *value = defaultLine->elements[2].item;
1419      while (*value && (*value == '"' || *value == '\'' ||      while (*value && (*value == '"' || *value == '\'' ||
# Line 1147  static struct grubConfig * readConfig(co Line 1431  static struct grubConfig * readConfig(co
1431      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1432      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1433   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1434      i = 0;      int i = 0;
1435      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1436   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1437      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 1170  static struct grubConfig * readConfig(co Line 1454  static struct grubConfig * readConfig(co
1454          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1455      }      }
1456   }   }
1457        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1458     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1459     if (defTitle) {
1460        int index = 0;
1461        if (isnumber(defTitle)) {
1462     index = atoi(defTitle);
1463     entry = findEntryByIndex(cfg, index);
1464        } else {
1465     entry = findEntryByTitle(cfg, defTitle, &index);
1466        }
1467        if (entry)
1468     cfg->defaultImage = index;
1469     }
1470      } else {      } else {
1471          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1472      }      }
# Line 1187  static void writeDefault(FILE * out, cha Line 1484  static void writeDefault(FILE * out, cha
1484    
1485      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1486   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1487      else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)      else if (cfg->cfi->defaultIsSaved) {
1488   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1489      else if (cfg->defaultImage > -1) {   if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1490        char *title;
1491        entry = findEntryByIndex(cfg, cfg->defaultImage);
1492        line = getLineByType(LT_MENUENTRY, entry->lines);
1493        if (!line)
1494     line = getLineByType(LT_TITLE, entry->lines);
1495        if (line) {
1496     title = extractTitle(line);
1497     if (title)
1498        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1499        }
1500     }
1501        } else if (cfg->defaultImage > -1) {
1502   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1503      if (cfg->cfi->defaultIsVariable) {      if (cfg->cfi->defaultIsVariable) {
1504          fprintf(out, "%sset default=\"%d\"\n", indent,          fprintf(out, "%sset default=\"%d\"\n", indent,
# Line 1249  static int writeConfig(struct grubConfig Line 1558  static int writeConfig(struct grubConfig
1558    
1559      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1560         directory to the dir of the symlink */         directory to the dir of the symlink */
1561              rc = chdir(dirname(strdupa(outName)));      char *dir = strdupa(outName);
1562        rc = chdir(dirname(dir));
1563      do {      do {
1564   buf = alloca(len + 1);   buf = alloca(len + 1);
1565   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1291  static int writeConfig(struct grubConfig Line 1601  static int writeConfig(struct grubConfig
1601      while (line) {      while (line) {
1602          if (line->type == LT_SET_VARIABLE && defaultKw &&          if (line->type == LT_SET_VARIABLE && defaultKw &&
1603   line->numElements == 3 &&   line->numElements == 3 &&
1604   !strcmp(line->elements[1].item, defaultKw->key)) {   !strcmp(line->elements[1].item, defaultKw->key) &&
1605     !is_special_grub2_variable(line->elements[2].item)) {
1606      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1607      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1608   } else if (line->type == LT_DEFAULT) {   } else if (line->type == LT_DEFAULT) {
# Line 1387  static char *findDiskForRoot() Line 1698  static char *findDiskForRoot()
1698      buf[rc] = '\0';      buf[rc] = '\0';
1699      chptr = buf;      chptr = buf;
1700    
1701        char *foundanswer = NULL;
1702    
1703      while (chptr && chptr != buf+rc) {      while (chptr && chptr != buf+rc) {
1704          devname = chptr;          devname = chptr;
1705    
# Line 1414  static char *findDiskForRoot() Line 1727  static char *findDiskForRoot()
1727           * for '/' obviously.           * for '/' obviously.
1728           */           */
1729          if (*(++chptr) == '/' && *(++chptr) == ' ') {          if (*(++chptr) == '/' && *(++chptr) == ' ') {
1730              /*              /* remember the last / entry in mtab */
1731               * Move back 2, which is the first space after the device name, set             foundanswer = devname;
              * it to \0 so strdup will just get the devicename.  
              */  
             chptr -= 2;  
             *chptr = '\0';  
             return strdup(devname);  
1732          }          }
1733    
1734          /* Next line */          /* Next line */
# Line 1429  static char *findDiskForRoot() Line 1737  static char *findDiskForRoot()
1737              chptr++;              chptr++;
1738      }      }
1739    
1740        /* Return the last / entry found */
1741        if (foundanswer) {
1742            chptr = strchr(foundanswer, ' ');
1743            *chptr = '\0';
1744            return strdup(foundanswer);
1745        }
1746    
1747      return NULL;      return NULL;
1748  }  }
1749    
1750  void printEntry(struct singleEntry * entry) {  void printEntry(struct singleEntry * entry, FILE *f) {
1751      int i;      int i;
1752      struct singleLine * line;      struct singleLine * line;
1753    
1754      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
1755   fprintf(stderr, "DBG: %s", line->indent);   log_message(f, "DBG: %s", line->indent);
1756   for (i = 0; i < line->numElements; i++) {   for (i = 0; i < line->numElements; i++) {
1757   fprintf(stderr, "%s%s",      /* Need to handle this, because we strip the quotes from
1758         * menuentry when read it. */
1759        if (line->type == LT_MENUENTRY && i == 1) {
1760     if(!isquote(*line->elements[i].item))
1761        log_message(f, "\'%s\'", line->elements[i].item);
1762     else
1763        log_message(f, "%s", line->elements[i].item);
1764     log_message(f, "%s", line->elements[i].indent);
1765    
1766     continue;
1767        }
1768        
1769        log_message(f, "%s%s",
1770      line->elements[i].item, line->elements[i].indent);      line->elements[i].item, line->elements[i].indent);
1771   }   }
1772   fprintf(stderr, "\n");   log_message(f, "\n");
1773      }      }
1774  }  }
1775    
1776  void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1777  {  {
1778      va_list argp;      static int once;
1779        va_list argp, argq;
1780    
1781        va_start(argp, fmt);
1782    
1783        va_copy(argq, argp);
1784        if (!once) {
1785     log_time(NULL);
1786     log_message(NULL, "command line: %s\n", saved_command_line);
1787        }
1788        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1789        log_vmessage(NULL, fmt, argq);
1790    
1791        printEntry(entry, NULL);
1792        va_end(argq);
1793    
1794      if (!debug)      if (!debug) {
1795     once = 1;
1796         va_end(argp);
1797   return;   return;
1798        }
1799    
1800      va_start(argp, fmt);      if (okay) {
1801     va_end(argp);
1802     return;
1803        }
1804    
1805        if (!once)
1806     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1807        once = 1;
1808      fprintf(stderr, "DBG: Image entry failed: ");      fprintf(stderr, "DBG: Image entry failed: ");
1809      vfprintf(stderr, fmt, argp);      vfprintf(stderr, fmt, argp);
1810      printEntry(entry);      printEntry(entry, stderr);
1811      va_end(argp);      va_end(argp);
1812  }  }
1813    
# Line 1483  int suitableImage(struct singleEntry * e Line 1834  int suitableImage(struct singleEntry * e
1834      char * rootdev;      char * rootdev;
1835    
1836      if (skipRemoved && entry->skip) {      if (skipRemoved && entry->skip) {
1837   notSuitablePrintf(entry, "marked to skip\n");   notSuitablePrintf(entry, 0, "marked to skip\n");
1838   return 0;   return 0;
1839      }      }
1840    
1841      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1842      if (!line) {      if (!line) {
1843   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1844   return 0;   return 0;
1845      }      }
1846      if (line->numElements < 2) {      if (line->numElements < 2) {
1847   notSuitablePrintf(entry, "line has only %d elements\n",   notSuitablePrintf(entry, 0, "line has only %d elements\n",
1848      line->numElements);      line->numElements);
1849   return 0;   return 0;
1850      }      }
1851    
1852      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1853        notSuitablePrintf(entry, 1, "\n");
1854        return 1;
1855        }
1856    
1857      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1858        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
# Line 1509  int suitableImage(struct singleEntry * e Line 1863  int suitableImage(struct singleEntry * e
1863      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1864              line->elements[1].item + rootspec_offset);              line->elements[1].item + rootspec_offset);
1865      if (access(fullName, R_OK)) {      if (access(fullName, R_OK)) {
1866   notSuitablePrintf(entry, "access to %s failed\n", fullName);   notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1867   return 0;   return 0;
1868      }      }
1869      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 1530  int suitableImage(struct singleEntry * e Line 1884  int suitableImage(struct singleEntry * e
1884    
1885              /* failed to find one */              /* failed to find one */
1886              if (!line) {              if (!line) {
1887   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1888   return 0;   return 0;
1889              }              }
1890    
# Line 1539  int suitableImage(struct singleEntry * e Line 1893  int suitableImage(struct singleEntry * e
1893      if (i < line->numElements)      if (i < line->numElements)
1894          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1895      else {      else {
1896   notSuitablePrintf(entry, "no root= entry found\n");   notSuitablePrintf(entry, 0, "no root= entry found\n");
1897   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1898          return 0;          return 0;
1899              }              }
# Line 1548  int suitableImage(struct singleEntry * e Line 1902  int suitableImage(struct singleEntry * e
1902    
1903      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1904      if (!getpathbyspec(dev)) {      if (!getpathbyspec(dev)) {
1905          notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);          notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1906          return 0;          return 0;
1907      } else      } else
1908   dev = getpathbyspec(dev);   dev = getpathbyspec(dev);
1909    
1910      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1911      if (!rootdev) {      if (!rootdev) {
1912          notSuitablePrintf(entry, "can't find root device\n");          notSuitablePrintf(entry, 0, "can't find root device\n");
1913   return 0;   return 0;
1914      }      }
1915    
1916      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1917          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1918   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1919          free(rootdev);          free(rootdev);
1920          return 0;          return 0;
1921      }      }
1922    
1923      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1924          notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1925   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1926   free(rootdev);   free(rootdev);
1927          return 0;          return 0;
1928      }      }
1929    
1930      free(rootdev);      free(rootdev);
1931        notSuitablePrintf(entry, 1, "\n");
1932    
1933      return 1;      return 1;
1934  }  }
# Line 1607  struct singleEntry * findEntryByPath(str Line 1962  struct singleEntry * findEntryByPath(str
1962   }   }
1963    
1964   indexVars[i + 1] = -1;   indexVars[i + 1] = -1;
1965    
1966   i = 0;   i = 0;
1967   if (index) {   if (index) {
1968      while (i < *index) i++;      while (i < *index) {
1969      if (indexVars[i] == -1) return NULL;   i++;
1970     if (indexVars[i] == -1) return NULL;
1971        }
1972   }   }
1973    
1974   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1975   if (!entry) return NULL;   if (!entry) return NULL;
1976    
1977   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1978   if (!line) return NULL;   if (!line) return NULL;
1979    
1980   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1655  struct singleEntry * findEntryByPath(str Line 2012  struct singleEntry * findEntryByPath(str
2012    
2013   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
2014      prefix = "";      prefix = "";
2015      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
2016      kernel += 6;      kernel += 6;
2017   }   }
2018    
# Line 1666  struct singleEntry * findEntryByPath(str Line 2023  struct singleEntry * findEntryByPath(str
2023    
2024      /* check all the lines matching checkType */      /* check all the lines matching checkType */
2025      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2026   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
2027       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
2028       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2029   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
2030        ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2031     line = getLineByType(ct, line);
2032     if (!line)
2033        break;  /* not found in this entry */
2034    
2035   if (line && line->numElements >= 2) {   if (line && line->type != LT_MENUENTRY &&
2036     line->numElements >= 2) {
2037      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
2038      if (!strcmp(line->elements[1].item +      if (!strcmp(line->elements[1].item +
2039   ((rootspec != NULL) ? strlen(rootspec) : 0),   ((rootspec != NULL) ? strlen(rootspec) : 0),
2040   kernel + strlen(prefix)))   kernel + strlen(prefix)))
2041   break;   break;
2042   }   }
2043     if(line->type == LT_MENUENTRY &&
2044     !strcmp(line->elements[1].item, kernel))
2045        break;
2046      }      }
2047    
2048      /* make sure this entry has a kernel identifier; this skips      /* make sure this entry has a kernel identifier; this skips
2049       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2050       * unfortunate)       * unfortunate)
2051       */       */
2052      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2053   break; /* found 'im! */   break; /* found 'im! */
2054   }   }
2055    
# Line 1694  struct singleEntry * findEntryByPath(str Line 2059  struct singleEntry * findEntryByPath(str
2059      return entry;      return entry;
2060  }  }
2061    
2062    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2063          int * index) {
2064        struct singleEntry * entry;
2065        struct singleLine * line;
2066        int i;
2067        char * newtitle;
2068    
2069        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2070     if (index && i < *index)
2071        continue;
2072     line = getLineByType(LT_TITLE, entry->lines);
2073     if (!line)
2074        line = getLineByType(LT_MENUENTRY, entry->lines);
2075     if (!line)
2076        continue;
2077     newtitle = grub2ExtractTitle(line);
2078     if (!newtitle)
2079        continue;
2080     if (!strcmp(title, newtitle))
2081        break;
2082        }
2083    
2084        if (!entry)
2085     return NULL;
2086    
2087        if (index)
2088     *index = i;
2089        return entry;
2090    }
2091    
2092  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2093      struct singleEntry * entry;      struct singleEntry * entry;
2094    
# Line 1716  struct singleEntry * findTemplate(struct Line 2111  struct singleEntry * findTemplate(struct
2111      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2112      int index;      int index;
2113    
2114      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2115     if (cfg->cfi->getEnv) {
2116        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2117        if (defTitle) {
2118     int index = 0;
2119     if (isnumber(defTitle)) {
2120        index = atoi(defTitle);
2121        entry = findEntryByIndex(cfg, index);
2122     } else {
2123        entry = findEntryByTitle(cfg, defTitle, &index);
2124     }
2125     if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2126        cfg->defaultImage = index;
2127        if (indexPtr)
2128     *indexPtr = index;
2129        return entry;
2130     }
2131        }
2132     }
2133        } else if (cfg->defaultImage > -1) {
2134   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2135   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2136      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1769  void markRemovedImage(struct grubConfig Line 2183  void markRemovedImage(struct grubConfig
2183        const char * prefix) {        const char * prefix) {
2184      struct singleEntry * entry;      struct singleEntry * entry;
2185    
2186      if (!image) return;      if (!image)
2187     return;
2188    
2189        /* check and see if we're removing the default image */
2190        if (isdigit(*image)) {
2191     entry = findEntryByPath(cfg, image, prefix, NULL);
2192     if(entry)
2193        entry->skip = 1;
2194     return;
2195        }
2196    
2197      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2198   entry->skip = 1;   entry->skip = 1;
# Line 1777  void markRemovedImage(struct grubConfig Line 2200  void markRemovedImage(struct grubConfig
2200    
2201  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2202       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2203       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2204      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2205      int i, j;      int i, j;
2206    
2207      if (newIsDefault) {      if (newIsDefault) {
2208   config->defaultImage = 0;   config->defaultImage = 0;
2209   return;   return;
2210        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2211     if (findEntryByIndex(config, index))
2212        config->defaultImage = index;
2213     else
2214        config->defaultImage = -1;
2215     return;
2216      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2217   i = 0;   i = 0;
2218   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1855  void displayEntry(struct singleEntry * e Line 2284  void displayEntry(struct singleEntry * e
2284      struct singleLine * line;      struct singleLine * line;
2285      char * root = NULL;      char * root = NULL;
2286      int i;      int i;
2287        int j;
2288    
2289      printf("index=%d\n", index);      printf("index=%d\n", index);
2290    
2291      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2292      if (!line) {      if (!line) {
2293          printf("non linux entry\n");          printf("non linux entry\n");
2294          return;          return;
2295      }      }
2296    
2297      printf("kernel=%s%s\n", prefix, line->elements[1].item);      if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2298     printf("kernel=%s\n", line->elements[1].item);
2299        else
2300     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2301    
2302      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2303   printf("args=\"");   printf("args=\"");
# Line 1920  void displayEntry(struct singleEntry * e Line 2353  void displayEntry(struct singleEntry * e
2353   printf("root=%s\n", s);   printf("root=%s\n", s);
2354      }      }
2355    
2356      line = getLineByType(LT_INITRD, entry->lines);      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2357    
2358      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2359   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2360        printf("initrd=");
2361     else
2362        printf("initrd=%s", prefix);
2363    
2364   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2365      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2366   printf("\n");   printf("\n");
# Line 1935  void displayEntry(struct singleEntry * e Line 2372  void displayEntry(struct singleEntry * e
2372      } else {      } else {
2373   char * title;   char * title;
2374   line = getLineByType(LT_MENUENTRY, entry->lines);   line = getLineByType(LT_MENUENTRY, entry->lines);
2375   title = grub2ExtractTitle(line);   if (line) {
2376   if (title)      title = grub2ExtractTitle(line);
2377      printf("title=%s\n", title);      if (title)
2378     printf("title=%s\n", title);
2379     }
2380        }
2381    
2382        for (j = 0, line = entry->lines; line; line = line->next) {
2383     if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
2384        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2385     printf("mbmodule%d=", j);
2386        else
2387     printf("mbmodule%d=%s", j, prefix);
2388    
2389        for (i = 1; i < line->numElements; i++)
2390     printf("%s%s", line->elements[i].item, line->elements[i].indent);
2391        printf("\n");
2392        j++;
2393     }
2394      }      }
2395  }  }
2396    
2397    int isSuseSystem(void) {
2398        const char * path;
2399        const static char default_path[] = "/etc/SuSE-release";
2400    
2401        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2402     path = default_path;
2403    
2404        if (!access(path, R_OK))
2405     return 1;
2406        return 0;
2407    }
2408    
2409    int isSuseGrubConf(const char * path) {
2410        FILE * grubConf;
2411        char * line = NULL;
2412        size_t len = 0, res = 0;
2413    
2414        grubConf = fopen(path, "r");
2415        if (!grubConf) {
2416            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2417     return 0;
2418        }
2419    
2420        while ((res = getline(&line, &len, grubConf)) != -1) {
2421     if (!strncmp(line, "setup", 5)) {
2422        fclose(grubConf);
2423        free(line);
2424        return 1;
2425     }
2426        }
2427    
2428        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2429          path);
2430    
2431        fclose(grubConf);
2432        free(line);
2433        return 0;
2434    }
2435    
2436    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2437        FILE * grubConf;
2438        char * line = NULL;
2439        size_t res = 0, len = 0;
2440    
2441        if (!path) return 1;
2442        if (!lbaPtr) return 1;
2443    
2444        grubConf = fopen(path, "r");
2445        if (!grubConf) return 1;
2446    
2447        while ((res = getline(&line, &len, grubConf)) != -1) {
2448     if (line[res - 1] == '\n')
2449        line[res - 1] = '\0';
2450     else if (len > res)
2451        line[res] = '\0';
2452     else {
2453        line = realloc(line, res + 1);
2454        line[res] = '\0';
2455     }
2456    
2457     if (!strncmp(line, "setup", 5)) {
2458        if (strstr(line, "--force-lba")) {
2459            *lbaPtr = 1;
2460        } else {
2461            *lbaPtr = 0;
2462        }
2463        dbgPrintf("lba: %i\n", *lbaPtr);
2464        break;
2465     }
2466        }
2467    
2468        free(line);
2469        fclose(grubConf);
2470        return 0;
2471    }
2472    
2473    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2474        FILE * grubConf;
2475        char * line = NULL;
2476        size_t res = 0, len = 0;
2477        char * lastParamPtr = NULL;
2478        char * secLastParamPtr = NULL;
2479        char installDeviceNumber = '\0';
2480        char * bounds = NULL;
2481    
2482        if (!path) return 1;
2483        if (!devicePtr) return 1;
2484    
2485        grubConf = fopen(path, "r");
2486        if (!grubConf) return 1;
2487    
2488        while ((res = getline(&line, &len, grubConf)) != -1) {
2489     if (strncmp(line, "setup", 5))
2490        continue;
2491    
2492     if (line[res - 1] == '\n')
2493        line[res - 1] = '\0';
2494     else if (len > res)
2495        line[res] = '\0';
2496     else {
2497        line = realloc(line, res + 1);
2498        line[res] = '\0';
2499     }
2500    
2501     lastParamPtr = bounds = line + res;
2502    
2503     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2504     while (!isspace(*lastParamPtr))
2505        lastParamPtr--;
2506     lastParamPtr++;
2507    
2508     secLastParamPtr = lastParamPtr - 2;
2509     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2510    
2511     if (lastParamPtr + 3 > bounds) {
2512        dbgPrintf("lastParamPtr going over boundary");
2513        fclose(grubConf);
2514        free(line);
2515        return 1;
2516     }
2517     if (!strncmp(lastParamPtr, "(hd", 3))
2518        lastParamPtr += 3;
2519     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2520    
2521     /*
2522     * Second last parameter will decide wether last parameter is
2523     * an IMAGE_DEVICE or INSTALL_DEVICE
2524     */
2525     while (!isspace(*secLastParamPtr))
2526        secLastParamPtr--;
2527     secLastParamPtr++;
2528    
2529     if (secLastParamPtr + 3 > bounds) {
2530        dbgPrintf("secLastParamPtr going over boundary");
2531        fclose(grubConf);
2532        free(line);
2533        return 1;
2534     }
2535     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2536     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2537        secLastParamPtr += 3;
2538        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2539        installDeviceNumber = *secLastParamPtr;
2540     } else {
2541        installDeviceNumber = *lastParamPtr;
2542     }
2543    
2544     *devicePtr = malloc(6);
2545     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2546     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2547     fclose(grubConf);
2548     free(line);
2549     return 0;
2550        }
2551    
2552        free(line);
2553        fclose(grubConf);
2554        return 1;
2555    }
2556    
2557    int grubGetBootFromDeviceMap(const char * device,
2558         char ** bootPtr) {
2559        FILE * deviceMap;
2560        char * line = NULL;
2561        size_t res = 0, len = 0;
2562        char * devicePtr;
2563        char * bounds = NULL;
2564        const char * path;
2565        const static char default_path[] = "/boot/grub/device.map";
2566    
2567        if (!device) return 1;
2568        if (!bootPtr) return 1;
2569    
2570        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2571     path = default_path;
2572    
2573        dbgPrintf("opening grub device.map file from: %s\n", path);
2574        deviceMap = fopen(path, "r");
2575        if (!deviceMap)
2576     return 1;
2577    
2578        while ((res = getline(&line, &len, deviceMap)) != -1) {
2579            if (!strncmp(line, "#", 1))
2580        continue;
2581    
2582     if (line[res - 1] == '\n')
2583        line[res - 1] = '\0';
2584     else if (len > res)
2585        line[res] = '\0';
2586     else {
2587        line = realloc(line, res + 1);
2588        line[res] = '\0';
2589     }
2590    
2591     devicePtr = line;
2592     bounds = line + res;
2593    
2594     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2595        devicePtr++;
2596     dbgPrintf("device: %s\n", devicePtr);
2597    
2598     if (!strncmp(devicePtr, device, strlen(device))) {
2599        devicePtr += strlen(device);
2600        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2601            devicePtr++;
2602    
2603        *bootPtr = strdup(devicePtr);
2604        break;
2605     }
2606        }
2607    
2608        free(line);
2609        fclose(deviceMap);
2610        return 0;
2611    }
2612    
2613    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2614        char * grubDevice;
2615    
2616        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2617     dbgPrintf("error looking for grub installation device\n");
2618        else
2619     dbgPrintf("grubby installation device: %s\n", grubDevice);
2620    
2621        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2622     dbgPrintf("error looking for grub boot device\n");
2623        else
2624     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2625    
2626        free(grubDevice);
2627        return 0;
2628    }
2629    
2630    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2631        /*
2632         * This SuSE grub configuration file at this location is not your average
2633         * grub configuration file, but instead the grub commands used to setup
2634         * grub on that system.
2635         */
2636        const char * path;
2637        const static char default_path[] = "/etc/grub.conf";
2638    
2639        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2640     path = default_path;
2641    
2642        if (!isSuseGrubConf(path)) return 1;
2643    
2644        if (lbaPtr) {
2645            *lbaPtr = 0;
2646            if (suseGrubConfGetLba(path, lbaPtr))
2647                return 1;
2648        }
2649    
2650        if (bootPtr) {
2651            *bootPtr = NULL;
2652            suseGrubConfGetBoot(path, bootPtr);
2653        }
2654    
2655        return 0;
2656    }
2657    
2658  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
2659      FILE * in;      FILE * in;
2660      char buf[1024];      char buf[1024];
# Line 1989  int parseSysconfigGrub(int * lbaPtr, cha Line 2703  int parseSysconfigGrub(int * lbaPtr, cha
2703  }  }
2704    
2705  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2706      char * boot;      char * boot = NULL;
2707      int lba;      int lba;
2708    
2709      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2710   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2711   if (boot) printf("boot=%s\n", boot);      free(boot);
2712        return;
2713     }
2714        } else {
2715            if (parseSysconfigGrub(&lba, &boot)) {
2716        free(boot);
2717        return;
2718     }
2719        }
2720    
2721        if (lba) printf("lba\n");
2722        if (boot) {
2723     printf("boot=%s\n", boot);
2724     free(boot);
2725      }      }
2726  }  }
2727    
# Line 2043  struct singleLine * addLineTmpl(struct s Line 2770  struct singleLine * addLineTmpl(struct s
2770  {  {
2771      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2772    
2773        if (isEfi && cfi == &grub2ConfigType) {
2774     enum lineType_e old = newLine->type;
2775     newLine->type = preferredLineType(newLine->type, cfi);
2776     if (old != newLine->type)
2777        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2778        }
2779    
2780      if (val) {      if (val) {
2781   /* override the inherited value with our own.   /* override the inherited value with our own.
2782   * This is a little weak because it only applies to elements[1]   * This is a little weak because it only applies to elements[1]
# Line 2052  struct singleLine * addLineTmpl(struct s Line 2786  struct singleLine * addLineTmpl(struct s
2786   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2787    
2788   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2789   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2790      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2791      if (rootspec != NULL) {      if (rootspec != NULL) {
2792   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 2089  struct singleLine *  addLine(struct sing Line 2823  struct singleLine *  addLine(struct sing
2823      /* NB: This function shouldn't allocate items on the heap, rather on the      /* NB: This function shouldn't allocate items on the heap, rather on the
2824       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2825       */       */
   
2826      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2827   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2828   tmpl.type = type;   tmpl.type = type;
# Line 2423  int updateActualImage(struct grubConfig Line 3156  int updateActualImage(struct grubConfig
3156      firstElement = 2;      firstElement = 2;
3157    
3158   } else {   } else {
3159      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3160      if (!line) {      if (!line) {
3161   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3162   continue;   continue;
# Line 2579  int updateImage(struct grubConfig * cfg, Line 3312  int updateImage(struct grubConfig * cfg,
3312      return rc;      return rc;
3313  }  }
3314    
3315    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3316     const char * image, const char * prefix, const char * initrd,
3317     const char * title) {
3318        struct singleEntry * entry;
3319        struct singleLine * line, * kernelLine, *endLine = NULL;
3320        int index = 0;
3321    
3322        if (!image) return 0;
3323    
3324        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3325            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3326            if (!kernelLine) continue;
3327    
3328     /* if title is supplied, the entry's title must match it. */
3329     if (title) {
3330        char *linetitle;
3331    
3332        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3333        if (!line)
3334     continue;
3335    
3336        linetitle = extractTitle(line);
3337        if (!linetitle)
3338     continue;
3339        if (strcmp(title, linetitle)) {
3340     free(linetitle);
3341     continue;
3342        }
3343        free(linetitle);
3344     }
3345    
3346            if (prefix) {
3347                int prefixLen = strlen(prefix);
3348                if (!strncmp(initrd, prefix, prefixLen))
3349                    initrd += prefixLen;
3350            }
3351     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3352     if (endLine)
3353        removeLine(entry, endLine);
3354            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3355     kernelLine->indent, initrd);
3356            if (!line)
3357        return 1;
3358     if (endLine) {
3359        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3360                if (!line)
3361     return 1;
3362     }
3363    
3364            break;
3365        }
3366    
3367        return 0;
3368    }
3369    
3370  int updateInitrd(struct grubConfig * cfg, const char * image,  int updateInitrd(struct grubConfig * cfg, const char * image,
3371                   const char * prefix, const char * initrd) {                   const char * prefix, const char * initrd, const char * title) {
3372      struct singleEntry * entry;      struct singleEntry * entry;
3373      struct singleLine * line, * kernelLine, *endLine = NULL;      struct singleLine * line, * kernelLine, *endLine = NULL;
3374      int index = 0;      int index = 0;
# Line 2588  int updateInitrd(struct grubConfig * cfg Line 3376  int updateInitrd(struct grubConfig * cfg
3376      if (!image) return 0;      if (!image) return 0;
3377    
3378      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3379          kernelLine = getLineByType(LT_KERNEL, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3380          if (!kernelLine) continue;          if (!kernelLine) continue;
3381    
3382          line = getLineByType(LT_INITRD, entry->lines);   /* if title is supplied, the entry's title must match it. */
3383     if (title) {
3384        char *linetitle;
3385    
3386        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3387        if (!line)
3388     continue;
3389    
3390        linetitle = extractTitle(line);
3391        if (!linetitle)
3392     continue;
3393        if (strcmp(title, linetitle)) {
3394     free(linetitle);
3395     continue;
3396        }
3397        free(linetitle);
3398     }
3399    
3400            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3401          if (line)          if (line)
3402              removeLine(entry, line);              removeLine(entry, line);
3403          if (prefix) {          if (prefix) {
# Line 2602  int updateInitrd(struct grubConfig * cfg Line 3408  int updateInitrd(struct grubConfig * cfg
3408   endLine = getLineByType(LT_ENTRY_END, entry->lines);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3409   if (endLine)   if (endLine)
3410      removeLine(entry, endLine);      removeLine(entry, endLine);
3411          line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);   enum lineType_e lt;
3412     switch(kernelLine->type) {
3413        case LT_KERNEL:
3414            lt = LT_INITRD;
3415     break;
3416        case LT_KERNEL_EFI:
3417            lt = LT_INITRD_EFI;
3418     break;
3419        case LT_KERNEL_16:
3420            lt = LT_INITRD_16;
3421     break;
3422        default:
3423            lt = preferredLineType(LT_INITRD, cfg->cfi);
3424     }
3425            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3426          if (!line)          if (!line)
3427      return 1;      return 1;
3428   if (endLine) {   if (endLine) {
# Line 2808  int checkForGrub(struct grubConfig * con Line 3628  int checkForGrub(struct grubConfig * con
3628      int fd;      int fd;
3629      unsigned char bootSect[512];      unsigned char bootSect[512];
3630      char * boot;      char * boot;
3631        int onSuse = isSuseSystem();
3632    
3633      if (parseSysconfigGrub(NULL, &boot))  
3634   return 0;      if (onSuse) {
3635     if (parseSuseGrubConf(NULL, &boot))
3636        return 0;
3637        } else {
3638     if (parseSysconfigGrub(NULL, &boot))
3639        return 0;
3640        }
3641    
3642      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3643      if (!boot)      if (!boot)
# Line 2829  int checkForGrub(struct grubConfig * con Line 3656  int checkForGrub(struct grubConfig * con
3656      }      }
3657      close(fd);      close(fd);
3658    
3659        /* The more elaborate checks do not work on SuSE. The checks done
3660         * seem to be reasonble (at least for now), so just return success
3661         */
3662        if (onSuse)
3663     return 2;
3664    
3665      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3666  }  }
3667    
# Line 2862  int checkForExtLinux(struct grubConfig * Line 3695  int checkForExtLinux(struct grubConfig *
3695      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3696  }  }
3697    
3698    int checkForYaboot(struct grubConfig * config) {
3699        /*
3700         * This is a simplistic check that we consider good enough for own puporses
3701         *
3702         * If we were to properly check if yaboot is *installed* we'd need to:
3703         * 1) get the system boot device (LT_BOOT)
3704         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3705         *    the content on the boot device
3706         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3707         * 4) check again if binary and boot device contents match
3708         */
3709        if (!access("/etc/yaboot.conf", R_OK))
3710     return 2;
3711    
3712        return 1;
3713    }
3714    
3715    int checkForElilo(struct grubConfig * config) {
3716        if (!access("/etc/elilo.conf", R_OK))
3717     return 2;
3718    
3719        return 1;
3720    }
3721    
3722  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3723      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3724    
# Line 2876  static char * getRootSpecifier(char * st Line 3733  static char * getRootSpecifier(char * st
3733  static char * getInitrdVal(struct grubConfig * config,  static char * getInitrdVal(struct grubConfig * config,
3734     const char * prefix, struct singleLine *tmplLine,     const char * prefix, struct singleLine *tmplLine,
3735     const char * newKernelInitrd,     const char * newKernelInitrd,
3736     char ** extraInitrds, int extraInitrdCount)     const char ** extraInitrds, int extraInitrdCount)
3737  {  {
3738      char *initrdVal, *end;      char *initrdVal, *end;
3739      int i;      int i;
# Line 2921  static char * getInitrdVal(struct grubCo Line 3778  static char * getInitrdVal(struct grubCo
3778    
3779  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3780           const char * prefix,           const char * prefix,
3781   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3782   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3783   char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3784                   char * newMBKernel, char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3785     const char * newDevTreePath) {
3786      struct singleEntry * new;      struct singleEntry * new;
3787      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3788      int needs;      int needs;
# Line 2965  int addNewKernel(struct grubConfig * con Line 3823  int addNewKernel(struct grubConfig * con
3823          needs |= NEED_MB;          needs |= NEED_MB;
3824          new->multiboot = 1;          new->multiboot = 1;
3825      }      }
3826        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3827     needs |= NEED_DEVTREE;
3828    
3829      if (template) {      if (template) {
3830   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 2978  int addNewKernel(struct grubConfig * con Line 3838  int addNewKernel(struct grubConfig * con
3838      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3839      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3840    
3841      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
     tmplLine->numElements >= 2) {  
3842   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3843      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3844       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 3056  int addNewKernel(struct grubConfig * con Line 3915  int addNewKernel(struct grubConfig * con
3915      /* template is multi but new is not,      /* template is multi but new is not,
3916       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3917       */       */
3918      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3919      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3920      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3921   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3922     config->cfi)->key);
3923      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3924    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3925      config->cfi);
3926      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3927   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3928      char *initrdVal;      char *initrdVal;
3929      /* template is multi but new is not,      /* template is multi but new is not,
3930       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3931       */       */
3932      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3933      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3934      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3935   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3936     config->cfi)->key);
3937      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3938      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3939      free(initrdVal);      free(initrdVal);
3940      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3941   }   }
3942    
3943      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3944   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3945      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3946      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 3133  int addNewKernel(struct grubConfig * con Line 3994  int addNewKernel(struct grubConfig * con
3994      static const char *prefix = "'Loading ";      static const char *prefix = "'Loading ";
3995      if (tmplLine->numElements > 1 &&      if (tmplLine->numElements > 1 &&
3996      strstr(tmplLine->elements[1].item, prefix) &&      strstr(tmplLine->elements[1].item, prefix) &&
3997      masterLine->next && masterLine->next->type == LT_KERNEL) {      masterLine->next &&
3998        iskernel(masterLine->next->type)) {
3999   char *newTitle = malloc(strlen(prefix) +   char *newTitle = malloc(strlen(prefix) +
4000   strlen(newKernelTitle) + 2);   strlen(newKernelTitle) + 2);
4001    
# Line 3148  int addNewKernel(struct grubConfig * con Line 4010  int addNewKernel(struct grubConfig * con
4010   newLine = addLineTmpl(new, tmplLine, newLine, NULL,   newLine = addLineTmpl(new, tmplLine, newLine, NULL,
4011   config->cfi);   config->cfi);
4012      }      }
4013        } else if (tmplLine->type == LT_DEVTREE &&
4014           tmplLine->numElements == 2 && newDevTreePath) {
4015            newLine = addLineTmpl(new, tmplLine, newLine,
4016          newDevTreePath + strlen(prefix),
4017          config->cfi);
4018     needs &= ~NEED_DEVTREE;
4019        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
4020     const char *ndtp = newDevTreePath;
4021     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
4022        ndtp += strlen(prefix);
4023     newLine = addLine(new, config->cfi, LT_DEVTREE,
4024      config->secondaryIndent,
4025      ndtp);
4026     needs &= ~NEED_DEVTREE;
4027     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4028      } else {      } else {
4029   /* pass through other lines from the template */   /* pass through other lines from the template */
4030   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 3160  int addNewKernel(struct grubConfig * con Line 4037  int addNewKernel(struct grubConfig * con
4037   */   */
4038   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
4039      case LT_KERNEL:      case LT_KERNEL:
4040        case LT_KERNEL_EFI:
4041        case LT_KERNEL_16:
4042   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
4043      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
4044   } else {   } else {
4045      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
4046              preferredLineType(LT_KERNEL, config->cfi),
4047        config->primaryIndent,        config->primaryIndent,
4048        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
4049      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 3220  int addNewKernel(struct grubConfig * con Line 4100  int addNewKernel(struct grubConfig * con
4100   }   }
4101      }      }
4102    
4103        struct singleLine *endLine = NULL;
4104        endLine = getLineByType(LT_ENTRY_END, new->lines);
4105        if (endLine) {
4106        removeLine(new, endLine);
4107        needs |= NEED_END;
4108        }
4109    
4110      /* add the remainder of the lines, i.e. those that either      /* add the remainder of the lines, i.e. those that either
4111       * weren't present in the template, or in the case of no template,       * weren't present in the template, or in the case of no template,
4112       * all the lines following the entryStart.       * all the lines following the entryStart.
# Line 3239  int addNewKernel(struct grubConfig * con Line 4126  int addNewKernel(struct grubConfig * con
4126      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
4127   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4128    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4129        config->cfi)) ?        config->cfi))
4130    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
4131     : preferredLineType(LT_KERNEL, config->cfi),
4132    config->secondaryIndent,    config->secondaryIndent,
4133    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
4134   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 3256  int addNewKernel(struct grubConfig * con Line 4144  int addNewKernel(struct grubConfig * con
4144   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4145   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4146    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4147        config->cfi)) ?        config->cfi))
4148    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
4149       : preferredLineType(LT_INITRD, config->cfi),
4150    config->secondaryIndent,    config->secondaryIndent,
4151    initrdVal);    initrdVal);
4152   free(initrdVal);   free(initrdVal);
4153   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4154      }      }
4155        if (needs & NEED_DEVTREE) {
4156     newLine = addLine(new, config->cfi, LT_DEVTREE,
4157      config->secondaryIndent,
4158      newDevTreePath);
4159     needs &= ~NEED_DEVTREE;
4160        }
4161    
4162        /* NEEDS_END must be last on bootloaders that need it... */
4163      if (needs & NEED_END) {      if (needs & NEED_END) {
4164   newLine = addLine(new, config->cfi, LT_ENTRY_END,   newLine = addLine(new, config->cfi, LT_ENTRY_END,
4165   config->secondaryIndent, NULL);   config->secondaryIndent, NULL);
# Line 3289  static void traceback(int signum) Line 4186  static void traceback(int signum)
4186      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
4187      size = backtrace(array, 40);      size = backtrace(array, 40);
4188    
4189      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4190              (unsigned long)size);              (unsigned long)size);
4191      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
4192      exit(1);      exit(1);
# Line 3314  int main(int argc, const char ** argv) { Line 4211  int main(int argc, const char ** argv) {
4211      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4212      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4213      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4214      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4215      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4216      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4217      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 3324  int main(int argc, const char ** argv) { Line 4221  int main(int argc, const char ** argv) {
4221      char * removeArgs = NULL;      char * removeArgs = NULL;
4222      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4223      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4224        char * envPath = NULL;
4225      const char * chptr = NULL;      const char * chptr = NULL;
4226      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4227      struct grubConfig * config;      struct grubConfig * config;
# Line 3332  int main(int argc, const char ** argv) { Line 4230  int main(int argc, const char ** argv) {
4230      int displayDefault = 0;      int displayDefault = 0;
4231      int displayDefaultIndex = 0;      int displayDefaultIndex = 0;
4232      int displayDefaultTitle = 0;      int displayDefaultTitle = 0;
4233        int defaultIndex = -1;
4234      struct poptOption options[] = {      struct poptOption options[] = {
4235   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4236      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 3349  int main(int argc, const char ** argv) { Line 4248  int main(int argc, const char ** argv) {
4248   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4249      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4250      _("bootfs") },      _("bootfs") },
4251  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4252   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4253      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4254  #endif  #endif
4255   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4256      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 3370  int main(int argc, const char ** argv) { Line 4269  int main(int argc, const char ** argv) {
4269      _("display the index of the default kernel") },      _("display the index of the default kernel") },
4270   { "default-title", 0, 0, &displayDefaultTitle, 0,   { "default-title", 0, 0, &displayDefaultTitle, 0,
4271      _("display the title of the default kernel") },      _("display the title of the default kernel") },
4272     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4273        _("device tree file for new stanza"), _("dtb-path") },
4274     { "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4275        _("device tree directory for new stanza"), _("dtb-path") },
4276   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4277      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4278     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4279        _("force grub2 stanzas to use efi") },
4280     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4281        _("path for environment data"),
4282        _("path") },
4283   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4284      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4285   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
# Line 3384  int main(int argc, const char ** argv) { Line 4292  int main(int argc, const char ** argv) {
4292   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4293      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4294   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4295      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4296   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4297      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4298   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 3404  int main(int argc, const char ** argv) { Line 4312  int main(int argc, const char ** argv) {
4312   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4313      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4314        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4315     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4316        _("make the given entry index the default entry"),
4317        _("entry-index") },
4318   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4319      _("configure silo bootloader") },      _("configure silo bootloader") },
4320   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 3425  int main(int argc, const char ** argv) { Line 4336  int main(int argc, const char ** argv) {
4336    
4337      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4338    
4339        int i = 0;
4340        for (int j = 1; j < argc; j++)
4341     i += strlen(argv[j]) + 1;
4342        saved_command_line = malloc(i);
4343        if (!saved_command_line) {
4344     fprintf(stderr, "grubby: %m\n");
4345     exit(1);
4346        }
4347        saved_command_line[0] = '\0';
4348        for (int j = 1; j < argc; j++) {
4349     strcat(saved_command_line, argv[j]);
4350     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4351        }
4352    
4353      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4354      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4355    
# Line 3468  int main(int argc, const char ** argv) { Line 4393  int main(int argc, const char ** argv) {
4393   return 1;   return 1;
4394      } else if (configureGrub2) {      } else if (configureGrub2) {
4395   cfi = &grub2ConfigType;   cfi = &grub2ConfigType;
4396     if (envPath)
4397        cfi->envFile = envPath;
4398      } else if (configureLilo) {      } else if (configureLilo) {
4399   cfi = &liloConfigType;   cfi = &liloConfigType;
4400      } else if (configureGrub) {      } else if (configureGrub) {
# Line 3486  int main(int argc, const char ** argv) { Line 4413  int main(int argc, const char ** argv) {
4413      }      }
4414    
4415      if (!cfi) {      if (!cfi) {
4416            if (grub2FindConfig(&grub2ConfigType))
4417        cfi = &grub2ConfigType;
4418     else
4419        #ifdef __ia64__        #ifdef __ia64__
4420   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4421        #elif __powerpc__        #elif __powerpc__
4422   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4423        #elif __sparc__        #elif __sparc__
4424          cfi = &siloConfigType;              cfi = &siloConfigType;
4425        #elif __s390__        #elif __s390__
4426          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4427        #elif __s390x__        #elif __s390x__
4428          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4429        #else        #else
         if (grub2FindConfig(&grub2ConfigType))  
     cfi = &grub2ConfigType;  
  else  
4430      cfi = &grubConfigType;      cfi = &grubConfigType;
4431        #endif        #endif
4432      }      }
# Line 3511  int main(int argc, const char ** argv) { Line 4438  int main(int argc, const char ** argv) {
4438      grubConfig = cfi->defaultConfig;      grubConfig = cfi->defaultConfig;
4439      }      }
4440    
4441      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4442    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4443    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4444        (defaultIndex >= 0))) {
4445   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4446    "specified option"));    "specified option"));
4447   return 1;   return 1;
4448      }      }
4449    
4450      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4451     removeKernelPath)) {     removeKernelPath)) {
4452   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4453    "be used when adding or removing kernels\n"));    "be used when adding or removing kernels\n"));
# Line 3529  int main(int argc, const char ** argv) { Line 4457  int main(int argc, const char ** argv) {
4457      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4458   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4459   return 1;   return 1;
4460      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||      } else if (!newKernelPath && (copyDefault ||
4461    (newKernelInitrd && !updateKernelPath)||    (newKernelInitrd && !updateKernelPath)||
4462    makeDefault || extraInitrdCount > 0)) {    makeDefault || extraInitrdCount > 0)) {
4463   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
# Line 3555  int main(int argc, const char ** argv) { Line 4483  int main(int argc, const char ** argv) {
4483   makeDefault = 1;   makeDefault = 1;
4484   defaultKernel = NULL;   defaultKernel = NULL;
4485      }      }
4486        else if (defaultKernel && (defaultIndex >= 0)) {
4487     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4488      "may not be used together\n"));
4489     return 1;
4490        }
4491    
4492      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4493   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
# Line 3563  int main(int argc, const char ** argv) { Line 4496  int main(int argc, const char ** argv) {
4496      }      }
4497    
4498      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4499   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4500          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4501     && (defaultIndex == -1)) {
4502   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4503   return 1;   return 1;
4504      }      }
# Line 3591  int main(int argc, const char ** argv) { Line 4525  int main(int argc, const char ** argv) {
4525      }      }
4526    
4527      if (bootloaderProbe) {      if (bootloaderProbe) {
4528   int lrc = 0, grc = 0, gr2c = 0, erc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4529   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4530    
4531   const char *grub2config = grub2FindConfig(&grub2ConfigType);   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4532   if (grub2config) {   if (grub2config) {
# Line 3620  int main(int argc, const char ** argv) { Line 4554  int main(int argc, const char ** argv) {
4554   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4555   }   }
4556    
4557     if (!access(eliloConfigType.defaultConfig, F_OK)) {
4558        econfig = readConfig(eliloConfigType.defaultConfig,
4559     &eliloConfigType);
4560        if (!econfig)
4561     erc = 1;
4562        else
4563     erc = checkForElilo(econfig);
4564     }
4565    
4566   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4567      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4568      if (!lconfig)      if (!lconfig)
4569   erc = 1;   extrc = 1;
4570      else      else
4571   erc = checkForExtLinux(lconfig);   extrc = checkForExtLinux(lconfig);
4572   }   }
4573    
4574   if (lrc == 1 || grc == 1 || gr2c == 1) return 1;  
4575     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4576        yconfig = readConfig(yabootConfigType.defaultConfig,
4577     &yabootConfigType);
4578        if (!yconfig)
4579     yrc = 1;
4580        else
4581     yrc = checkForYaboot(yconfig);
4582     }
4583    
4584     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4585     erc == 1)
4586        return 1;
4587    
4588   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4589   if (gr2c == 2) printf("grub2\n");   if (gr2c == 2) printf("grub2\n");
4590   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4591   if (erc == 2) printf("extlinux\n");   if (extrc == 2) printf("extlinux\n");
4592     if (yrc == 2) printf("yaboot\n");
4593     if (erc == 2) printf("elilo\n");
4594    
4595   return 0;   return 0;
4596      }      }
4597    
4598        if (grubConfig == NULL) {
4599     printf("Could not find bootloader configuration file.\n");
4600     exit(1);
4601        }
4602    
4603      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4604      if (!config) return 1;      if (!config) return 1;
4605    
# Line 3647  int main(int argc, const char ** argv) { Line 4609  int main(int argc, const char ** argv) {
4609          char * rootspec;          char * rootspec;
4610    
4611   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4612     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4613     cfi->defaultIsSaved)
4614        config->defaultImage = 0;
4615   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4616   if (!entry) return 0;   if (!entry) return 0;
4617   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4618    
4619   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
4620   if (!line) return 0;   if (!line) return 0;
4621    
4622          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 3665  int main(int argc, const char ** argv) { Line 4630  int main(int argc, const char ** argv) {
4630   struct singleEntry * entry;   struct singleEntry * entry;
4631    
4632   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4633     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4634     cfi->defaultIsSaved)
4635        config->defaultImage = 0;
4636   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4637   if (!entry) return 0;   if (!entry) return 0;
4638    
# Line 3687  int main(int argc, const char ** argv) { Line 4655  int main(int argc, const char ** argv) {
4655    
4656      } else if (displayDefaultIndex) {      } else if (displayDefaultIndex) {
4657          if (config->defaultImage == -1) return 0;          if (config->defaultImage == -1) return 0;
4658     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4659     cfi->defaultIsSaved)
4660        config->defaultImage = 0;
4661          printf("%i\n", config->defaultImage);          printf("%i\n", config->defaultImage);
4662            return 0;
4663    
4664      } else if (kernelInfo)      } else if (kernelInfo)
4665   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
# Line 3700  int main(int argc, const char ** argv) { Line 4672  int main(int argc, const char ** argv) {
4672      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4673      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4674      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4675      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4676      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4677      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4678                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4679      if (updateKernelPath && newKernelInitrd) {      if (updateKernelPath && newKernelInitrd) {
4680              if (updateInitrd(config, updateKernelPath, bootPrefix,      if (newMBKernel) {
4681                               newKernelInitrd)) return 1;      if (addMBInitrd(config, newMBKernel, updateKernelPath,
4682     bootPrefix, newKernelInitrd,
4683     newKernelTitle))
4684        return 1;
4685        } else {
4686        if (updateInitrd(config, updateKernelPath, bootPrefix,
4687     newKernelInitrd, newKernelTitle))
4688     return 1;
4689        }
4690      }      }
4691      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4692                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4693                       extraInitrds, extraInitrdCount,                       (const char **)extraInitrds, extraInitrdCount,
4694                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4695            
4696    
4697      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {

Legend:
Removed from v.1800  
changed lines
  Added in v.2976