Magellan Linux

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

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

revision 1717 by niro, Sat Feb 18 00:47:17 2012 UTC revision 2250 by niro, Mon Oct 21 13:56:22 2013 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 46  Line 48 
48  #define dbgPrintf(format, args...)  #define dbgPrintf(format, args...)
49  #endif  #endif
50    
51    int debug = 0; /* Currently just for template debugging */
52    
53  #define _(A) (A)  #define _(A) (A)
54    
55  #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */  #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
56  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
57    
58    #define NOOP_OPCODE 0x90
59    #define JMP_SHORT_OPCODE 0xeb
60    
61    int isEfi = 0;
62    
63    char *saved_command_line = NULL;
64    
65  /* comments get lumped in with indention */  /* comments get lumped in with indention */
66  struct lineElement {  struct lineElement {
67      char * item;      char * item;
# Line 77  enum lineType_e { Line 88  enum lineType_e {
88      LT_MENUENTRY    = 1 << 17,      LT_MENUENTRY    = 1 << 17,
89      LT_ENTRY_END    = 1 << 18,      LT_ENTRY_END    = 1 << 18,
90      LT_SET_VARIABLE = 1 << 19,      LT_SET_VARIABLE = 1 << 19,
91      LT_UNKNOWN      = 1 << 20,      LT_KERNEL_EFI   = 1 << 20,
92        LT_INITRD_EFI   = 1 << 21,
93        LT_UNKNOWN      = 1 << 22,
94  };  };
95    
96  struct singleLine {  struct singleLine {
# Line 109  struct singleEntry { Line 122  struct singleEntry {
122    
123  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
124  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
125    #define DEFAULT_SAVED_GRUB2 -3
126    
127  struct keywordTypes {  struct keywordTypes {
128      char * key;      char * key;
# Line 128  struct configFileInfo { Line 142  struct configFileInfo {
142      findConfigFunc findConfig;      findConfigFunc findConfig;
143      writeLineFunc writeLine;      writeLineFunc writeLine;
144      struct keywordTypes * keywords;      struct keywordTypes * keywords;
145        int caseInsensitive;
146      int defaultIsIndex;      int defaultIsIndex;
147      int defaultIsVariable;      int defaultIsVariable;
148      int defaultSupportSaved;      int defaultSupportSaved;
# Line 158  struct keywordTypes grubKeywords[] = { Line 173  struct keywordTypes grubKeywords[] = {
173    
174  const char *grubFindConfig(struct configFileInfo *cfi) {  const char *grubFindConfig(struct configFileInfo *cfi) {
175      static const char *configFiles[] = {      static const char *configFiles[] = {
  "/etc/grub.conf",  
176   "/boot/grub/grub.conf",   "/boot/grub/grub.conf",
177   "/boot/grub/menu.lst",   "/boot/grub/menu.lst",
178     "/etc/grub.conf",
179   NULL   NULL
180      };      };
181      static int i = -1;      static int i = -1;
# Line 199  struct keywordTypes grub2Keywords[] = { Line 214  struct keywordTypes grub2Keywords[] = {
214      { "default",    LT_DEFAULT,     ' ' },      { "default",    LT_DEFAULT,     ' ' },
215      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
216      { "linux",      LT_KERNEL,      ' ' },      { "linux",      LT_KERNEL,      ' ' },
217        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
218      { "initrd",     LT_INITRD,      ' ', ' ' },      { "initrd",     LT_INITRD,      ' ', ' ' },
219        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
220      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
221      { "kernel",     LT_HYPER,       ' ' },      { "kernel",     LT_HYPER,       ' ' },
222      { NULL, 0, 0 },      { NULL, 0, 0 },
# Line 213  const char *grub2FindConfig(struct confi Line 230  const char *grub2FindConfig(struct confi
230      };      };
231      static int i = -1;      static int i = -1;
232      static const char *grub_cfg = "/boot/grub/grub.cfg";      static const char *grub_cfg = "/boot/grub/grub.cfg";
233        int rc = -1;
234    
235      if (i == -1) {      if (i == -1) {
236   for (i = 0; configFiles[i] != NULL; i++) {   for (i = 0; configFiles[i] != NULL; i++) {
237      dbgPrintf("Checking \"%s\": ", configFiles[i]);      dbgPrintf("Checking \"%s\": ", configFiles[i]);
238      if (!access(configFiles[i], R_OK)) {      if ((rc = access(configFiles[i], R_OK))) {
239     if (errno == EACCES) {
240        printf("Unable to access bootloader configuration file "
241           "\"%s\": %m\n", configFiles[i]);
242        exit(1);
243     }
244     continue;
245        } else {
246   dbgPrintf("found\n");   dbgPrintf("found\n");
247   return configFiles[i];   return configFiles[i];
248      }      }
# Line 236  const char *grub2FindConfig(struct confi Line 261  const char *grub2FindConfig(struct confi
261      return configFiles[i];      return configFiles[i];
262  }  }
263    
264    int sizeOfSingleLine(struct singleLine * line) {
265      int count = 0;
266    
267      for (int i = 0; i < line->numElements; i++) {
268        int indentSize = 0;
269    
270        count = count + strlen(line->elements[i].item);
271    
272        indentSize = strlen(line->elements[i].indent);
273        if (indentSize > 0)
274          count = count + indentSize;
275        else
276          /* be extra safe and add room for whitespaces */
277          count = count + 1;
278      }
279    
280      /* room for trailing terminator */
281      count = count + 1;
282    
283      return count;
284    }
285    
286    static int isquote(char q)
287    {
288        if (q == '\'' || q == '\"')
289     return 1;
290        return 0;
291    }
292    
293    static int iskernel(enum lineType_e type) {
294        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
295    }
296    
297    static int isinitrd(enum lineType_e type) {
298        return (type == LT_INITRD || type == LT_INITRD_EFI);
299    }
300    
301    char *grub2ExtractTitle(struct singleLine * line) {
302        char * current;
303        char * current_indent;
304        int current_len;
305        int current_indent_len;
306        int i;
307    
308        /* bail out if line does not start with menuentry */
309        if (strcmp(line->elements[0].item, "menuentry"))
310          return NULL;
311    
312        i = 1;
313        current = line->elements[i].item;
314        current_len = strlen(current);
315    
316        /* if second word is quoted, strip the quotes and return single word */
317        if (isquote(*current) && isquote(current[current_len - 1])) {
318     char *tmp;
319    
320     tmp = strdup(current);
321     *(tmp + current_len - 1) = '\0';
322     return ++tmp;
323        }
324    
325        /* if no quotes, return second word verbatim */
326        if (!isquote(*current))
327     return current;
328    
329        /* second element start with a quote, so we have to find the element
330         * whose last character is also quote (assuming it's the closing one) */
331        int resultMaxSize;
332        char * result;
333        
334        resultMaxSize = sizeOfSingleLine(line);
335        result = malloc(resultMaxSize);
336        snprintf(result, resultMaxSize, "%s", ++current);
337        
338        i++;
339        for (; i < line->numElements; ++i) {
340     current = line->elements[i].item;
341     current_len = strlen(current);
342     current_indent = line->elements[i].indent;
343     current_indent_len = strlen(current_indent);
344    
345     strncat(result, current_indent, current_indent_len);
346     if (!isquote(current[current_len-1])) {
347        strncat(result, current, current_len);
348     } else {
349        strncat(result, current, current_len - 1);
350        break;
351     }
352        }
353        return result;
354    }
355    
356  struct configFileInfo grub2ConfigType = {  struct configFileInfo grub2ConfigType = {
357      .findConfig = grub2FindConfig,      .findConfig = grub2FindConfig,
358      .keywords = grub2Keywords,      .keywords = grub2Keywords,
359      .defaultIsIndex = 1,      .defaultIsIndex = 1,
360      .defaultSupportSaved = 0,      .defaultSupportSaved = 1,
361      .defaultIsVariable = 1,      .defaultIsVariable = 1,
362      .entryStart = LT_MENUENTRY,      .entryStart = LT_MENUENTRY,
363      .entryEnd = LT_ENTRY_END,      .entryEnd = LT_ENTRY_END,
# Line 392  struct configFileInfo ziplConfigType = { Line 509  struct configFileInfo ziplConfigType = {
509  struct configFileInfo extlinuxConfigType = {  struct configFileInfo extlinuxConfigType = {
510      .defaultConfig = "/boot/extlinux/extlinux.conf",      .defaultConfig = "/boot/extlinux/extlinux.conf",
511      .keywords = extlinuxKeywords,      .keywords = extlinuxKeywords,
512        .caseInsensitive = 1,
513      .entryStart = LT_TITLE,      .entryStart = LT_TITLE,
514      .needsBootPrefix = 1,      .needsBootPrefix = 1,
515      .maxTitleLength = 255,      .maxTitleLength = 255,
# Line 480  static char * sdupprintf(const char *for Line 598  static char * sdupprintf(const char *for
598      return buf;      return buf;
599  }  }
600    
601    static enum lineType_e preferredLineType(enum lineType_e type,
602     struct configFileInfo *cfi) {
603        if (isEfi && cfi == &grub2ConfigType) {
604     switch (type) {
605     case LT_KERNEL:
606        return LT_KERNEL_EFI;
607     case LT_INITRD:
608        return LT_INITRD_EFI;
609     default:
610        return type;
611     }
612        }
613        return type;
614    }
615    
616  static struct keywordTypes * getKeywordByType(enum lineType_e type,  static struct keywordTypes * getKeywordByType(enum lineType_e type,
617        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
618      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
     for (kw = cfi->keywords; kw->key; kw++) {  
619   if (kw->type == type)   if (kw->type == type)
620      return kw;      return kw;
621      }      }
# Line 513  static char * getuuidbydev(char *device) Line 645  static char * getuuidbydev(char *device)
645    
646  static enum lineType_e getTypeByKeyword(char * keyword,  static enum lineType_e getTypeByKeyword(char * keyword,
647   struct configFileInfo * cfi) {   struct configFileInfo * cfi) {
648      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
649      for (kw = cfi->keywords; kw->key; kw++) {   if (cfi->caseInsensitive) {
650   if (!strcmp(keyword, kw->key))      if (!strcasecmp(keyword, kw->key))
651      return kw->type;                  return kw->type;
652     } else {
653        if (!strcmp(keyword, kw->key))
654            return kw->type;
655     }
656      }      }
657      return LT_UNKNOWN;      return LT_UNKNOWN;
658  }  }
# Line 601  static void lineInit(struct singleLine * Line 737  static void lineInit(struct singleLine *
737  }  }
738    
739  struct singleLine * lineDup(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
     int i;  
740      struct singleLine * newLine = malloc(sizeof(*newLine));      struct singleLine * newLine = malloc(sizeof(*newLine));
741    
742      newLine->indent = strdup(line->indent);      newLine->indent = strdup(line->indent);
# Line 611  struct singleLine * lineDup(struct singl Line 746  struct singleLine * lineDup(struct singl
746      newLine->elements = malloc(sizeof(*newLine->elements) *      newLine->elements = malloc(sizeof(*newLine->elements) *
747         newLine->numElements);         newLine->numElements);
748    
749      for (i = 0; i < newLine->numElements; i++) {      for (int i = 0; i < newLine->numElements; i++) {
750   newLine->elements[i].indent = strdup(line->elements[i].indent);   newLine->elements[i].indent = strdup(line->elements[i].indent);
751   newLine->elements[i].item = strdup(line->elements[i].item);   newLine->elements[i].item = strdup(line->elements[i].item);
752      }      }
# Line 620  struct singleLine * lineDup(struct singl Line 755  struct singleLine * lineDup(struct singl
755  }  }
756    
757  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
     int i;  
   
758      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
759    
760      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
761   free(line->elements[i].item);   free(line->elements[i].item);
762   free(line->elements[i].indent);   free(line->elements[i].indent);
763      }      }
# Line 635  static void lineFree(struct singleLine * Line 768  static void lineFree(struct singleLine *
768    
769  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
770       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
771      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
772    
773      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
774     /* Need to handle this, because we strip the quotes from
775     * menuentry when read it. */
776     if (line->type == LT_MENUENTRY && i == 1) {
777        if(!isquote(*line->elements[i].item))
778     fprintf(out, "\'%s\'", line->elements[i].item);
779        else
780     fprintf(out, "%s", line->elements[i].item);
781        fprintf(out, "%s", line->elements[i].indent);
782    
783        continue;
784     }
785    
786   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
787      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
788    
# Line 733  static int getNextLine(char ** bufPtr, s Line 876  static int getNextLine(char ** bufPtr, s
876      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
877   char * fullLine;   char * fullLine;
878   int len;   int len;
  int i;  
879    
880   len = strlen(line->indent);   len = strlen(line->indent);
881   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
882      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
883     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
884    
# Line 745  static int getNextLine(char ** bufPtr, s Line 887  static int getNextLine(char ** bufPtr, s
887   free(line->indent);   free(line->indent);
888   line->indent = fullLine;   line->indent = fullLine;
889    
890   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
891      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
892      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
893      free(line->elements[i].item);      free(line->elements[i].item);
# Line 764  static int getNextLine(char ** bufPtr, s Line 906  static int getNextLine(char ** bufPtr, s
906   * elements up more   * elements up more
907   */   */
908   if (!isspace(kw->separatorChar)) {   if (!isspace(kw->separatorChar)) {
     int i;  
909      char indent[2] = "";      char indent[2] = "";
910      indent[0] = kw->separatorChar;      indent[0] = kw->separatorChar;
911      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
912   char *p;   char *p;
  int j;  
913   int numNewElements;   int numNewElements;
914    
915   numNewElements = 0;   numNewElements = 0;
# Line 785  static int getNextLine(char ** bufPtr, s Line 925  static int getNextLine(char ** bufPtr, s
925      sizeof(*line->elements) * elementsAlloced);      sizeof(*line->elements) * elementsAlloced);
926   }   }
927    
928   for (j = line->numElements; j > i; j--) {   for (int j = line->numElements; j > i; j--) {
929   line->elements[j + numNewElements] = line->elements[j];   line->elements[j + numNewElements] = line->elements[j];
930   }   }
931   line->numElements += numNewElements;   line->numElements += numNewElements;
# Line 798  static int getNextLine(char ** bufPtr, s Line 938  static int getNextLine(char ** bufPtr, s
938   break;   break;
939   }   }
940    
941   free(line->elements[i].indent);   line->elements[i + 1].indent = line->elements[i].indent;
942   line->elements[i].indent = strdup(indent);   line->elements[i].indent = strdup(indent);
943   *p++ = '\0';   *p++ = '\0';
944   i++;   i++;
945   line->elements[i].item = strdup(p);   line->elements[i].item = strdup(p);
  line->elements[i].indent = strdup("");  
  p = line->elements[i].item;  
946   }   }
947      }      }
948   }   }
# Line 825  static struct grubConfig * readConfig(co Line 963  static struct grubConfig * readConfig(co
963      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
964      char * end;      char * end;
965      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
966      int i, len;      int len;
967      char * buf;      char * buf;
968    
969      if (!strcmp(inName, "-")) {      if (inName == NULL) {
970            printf("Could not find bootloader configuration\n");
971            exit(1);
972        } else if (!strcmp(inName, "-")) {
973   in = 0;   in = 0;
974      } else {      } else {
975   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 871  static struct grubConfig * readConfig(co Line 1012  static struct grubConfig * readConfig(co
1012      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1013   }   }
1014    
1015   if (isEntryStart(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1016      sawEntry = 1;      sawEntry = 1;
1017      if (!entry) {      if (!entry) {
1018   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 888  static struct grubConfig * readConfig(co Line 1029  static struct grubConfig * readConfig(co
1029   }   }
1030    
1031   if (line->type == LT_SET_VARIABLE) {   if (line->type == LT_SET_VARIABLE) {
     int i;  
1032      dbgPrintf("found 'set' command (%d elements): ", line->numElements);      dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1033      dbgPrintf("%s", line->indent);      dbgPrintf("%s", line->indent);
1034      for (i = 0; i < line->numElements; i++)      for (int i = 0; i < line->numElements; i++)
1035   dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);   dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1036      dbgPrintf("\n");      dbgPrintf("\n");
1037      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1038      if (kwType && line->numElements == 3 &&      if (kwType && line->numElements == 3 &&
# Line 905  static struct grubConfig * readConfig(co Line 1045  static struct grubConfig * readConfig(co
1045      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1046      defaultLine = line;      defaultLine = line;
1047    
1048          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1049      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1050       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1051       * instead of LT_KERNEL now       * instead of LT_KERNEL now
# Line 919  static struct grubConfig * readConfig(co Line 1059  static struct grubConfig * readConfig(co
1059       * This only applies to grub, but that's the only place we       * This only applies to grub, but that's the only place we
1060       * should find LT_MBMODULE lines anyway.       * should find LT_MBMODULE lines anyway.
1061       */       */
1062      struct singleLine * l;      for (struct singleLine *l = entry->lines; l; l = l->next) {
     for (l = entry->lines; l; l = l->next) {  
1063   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1064      break;      break;
1065   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1066      l->type = LT_HYPER;      l->type = LT_HYPER;
1067      break;      break;
1068   }   }
# Line 940  static struct grubConfig * readConfig(co Line 1079  static struct grubConfig * readConfig(co
1079   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1080      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1081      len = 0;      len = 0;
1082      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1083   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1084   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1085      }      }
1086      buf = malloc(len + 1);      buf = malloc(len + 1);
1087      *buf = '\0';      *buf = '\0';
1088    
1089      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1090   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1091   free(line->elements[i].item);   free(line->elements[i].item);
1092    
# Line 961  static struct grubConfig * readConfig(co Line 1100  static struct grubConfig * readConfig(co
1100      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1101      line->elements[1].item = buf;      line->elements[1].item = buf;
1102      line->numElements = 2;      line->numElements = 2;
1103     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1104        /* let --remove-kernel="TITLE=what" work */
1105        len = 0;
1106        char *extras;
1107        char *title;
1108    
1109        for (int i = 1; i < line->numElements; i++) {
1110     len += strlen(line->elements[i].item);
1111     len += strlen(line->elements[i].indent);
1112        }
1113        buf = malloc(len + 1);
1114        *buf = '\0';
1115    
1116        /* allocate mem for extra flags. */
1117        extras = malloc(len + 1);
1118        *extras = '\0';
1119    
1120        /* get title. */
1121        for (int i = 0; i < line->numElements; i++) {
1122     if (!strcmp(line->elements[i].item, "menuentry"))
1123        continue;
1124     if (isquote(*line->elements[i].item))
1125        title = line->elements[i].item + 1;
1126     else
1127        title = line->elements[i].item;
1128    
1129     len = strlen(title);
1130            if (isquote(title[len-1])) {
1131        strncat(buf, title,len-1);
1132        break;
1133     } else {
1134        strcat(buf, title);
1135        strcat(buf, line->elements[i].indent);
1136     }
1137        }
1138    
1139        /* get extras */
1140        int count = 0;
1141        for (int i = 0; i < line->numElements; i++) {
1142     if (count >= 2) {
1143        strcat(extras, line->elements[i].item);
1144        strcat(extras, line->elements[i].indent);
1145     }
1146    
1147     if (!strcmp(line->elements[i].item, "menuentry"))
1148        continue;
1149    
1150     /* count ' or ", there should be two in menuentry line. */
1151     if (isquote(*line->elements[i].item))
1152        count++;
1153    
1154     len = strlen(line->elements[i].item);
1155    
1156     if (isquote(line->elements[i].item[len -1]))
1157        count++;
1158    
1159     /* ok, we get the final ' or ", others are extras. */
1160                }
1161        line->elements[1].indent =
1162     line->elements[line->numElements - 2].indent;
1163        line->elements[1].item = buf;
1164        line->elements[2].indent =
1165     line->elements[line->numElements - 2].indent;
1166        line->elements[2].item = extras;
1167        line->numElements = 3;
1168   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1169      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1170         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 970  static struct grubConfig * readConfig(co Line 1173  static struct grubConfig * readConfig(co
1173      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1174   int last, len;   int last, len;
1175    
1176   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1177      memmove(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1178      strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1179    
1180   last = line->numElements - 1;   last = line->numElements - 1;
1181   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1182   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1183      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1184      }      }
1185   }   }
# Line 1035  static struct grubConfig * readConfig(co Line 1238  static struct grubConfig * readConfig(co
1238    
1239      dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");      dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1240      if (defaultLine) {      if (defaultLine) {
1241   if (cfi->defaultIsVariable) {          if (defaultLine->numElements > 2 &&
1242        cfi->defaultSupportSaved &&
1243        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1244        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1245     } else if (cfi->defaultIsVariable) {
1246      char *value = defaultLine->elements[2].item;      char *value = defaultLine->elements[2].item;
1247      while (*value && (*value == '"' || *value == '\'' ||      while (*value && (*value == '"' || *value == '\'' ||
1248      *value == ' ' || *value == '\t'))      *value == ' ' || *value == '\t'))
# Line 1052  static struct grubConfig * readConfig(co Line 1259  static struct grubConfig * readConfig(co
1259      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1260      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1261   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1262      i = 0;      int i = 0;
1263      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1264   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1265      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 1092  static void writeDefault(FILE * out, cha Line 1299  static void writeDefault(FILE * out, cha
1299    
1300      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1301   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1302        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1303     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1304      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1305   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1306      if (cfg->cfi->defaultIsVariable) {      if (cfg->cfi->defaultIsVariable) {
# Line 1152  static int writeConfig(struct grubConfig Line 1361  static int writeConfig(struct grubConfig
1361    
1362      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1363         directory to the dir of the symlink */         directory to the dir of the symlink */
1364              rc = chdir(dirname(strdupa(outName)));      char *dir = strdupa(outName);
1365        rc = chdir(dirname(dir));
1366      do {      do {
1367   buf = alloca(len + 1);   buf = alloca(len + 1);
1368   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1290  static char *findDiskForRoot() Line 1500  static char *findDiskForRoot()
1500      buf[rc] = '\0';      buf[rc] = '\0';
1501      chptr = buf;      chptr = buf;
1502    
1503        char *foundanswer = NULL;
1504    
1505      while (chptr && chptr != buf+rc) {      while (chptr && chptr != buf+rc) {
1506          devname = chptr;          devname = chptr;
1507    
# Line 1317  static char *findDiskForRoot() Line 1529  static char *findDiskForRoot()
1529           * for '/' obviously.           * for '/' obviously.
1530           */           */
1531          if (*(++chptr) == '/' && *(++chptr) == ' ') {          if (*(++chptr) == '/' && *(++chptr) == ' ') {
1532              /*              /* remember the last / entry in mtab */
1533               * 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);  
1534          }          }
1535    
1536          /* Next line */          /* Next line */
# Line 1332  static char *findDiskForRoot() Line 1539  static char *findDiskForRoot()
1539              chptr++;              chptr++;
1540      }      }
1541    
1542        /* Return the last / entry found */
1543        if (foundanswer) {
1544            chptr = strchr(foundanswer, ' ');
1545            *chptr = '\0';
1546            return strdup(foundanswer);
1547        }
1548    
1549      return NULL;      return NULL;
1550  }  }
1551    
1552    void printEntry(struct singleEntry * entry, FILE *f) {
1553        int i;
1554        struct singleLine * line;
1555    
1556        for (line = entry->lines; line; line = line->next) {
1557     log_message(f, "DBG: %s", line->indent);
1558     for (i = 0; i < line->numElements; i++) {
1559        /* Need to handle this, because we strip the quotes from
1560         * menuentry when read it. */
1561        if (line->type == LT_MENUENTRY && i == 1) {
1562     if(!isquote(*line->elements[i].item))
1563        log_message(f, "\'%s\'", line->elements[i].item);
1564     else
1565        log_message(f, "%s", line->elements[i].item);
1566     log_message(f, "%s", line->elements[i].indent);
1567    
1568     continue;
1569        }
1570        
1571        log_message(f, "%s%s",
1572        line->elements[i].item, line->elements[i].indent);
1573     }
1574     log_message(f, "\n");
1575        }
1576    }
1577    
1578    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1579    {
1580        static int once;
1581        va_list argp, argq;
1582    
1583        va_start(argp, fmt);
1584    
1585        va_copy(argq, argp);
1586        if (!once) {
1587     log_time(NULL);
1588     log_message(NULL, "command line: %s\n", saved_command_line);
1589        }
1590        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1591        log_vmessage(NULL, fmt, argq);
1592    
1593        printEntry(entry, NULL);
1594        va_end(argq);
1595    
1596        if (!debug) {
1597     once = 1;
1598         va_end(argp);
1599     return;
1600        }
1601    
1602        if (okay) {
1603     va_end(argp);
1604     return;
1605        }
1606    
1607        if (!once)
1608     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1609        once = 1;
1610        fprintf(stderr, "DBG: Image entry failed: ");
1611        vfprintf(stderr, fmt, argp);
1612        printEntry(entry, stderr);
1613        va_end(argp);
1614    }
1615    
1616    #define beginswith(s, c) ((s) && (s)[0] == (c))
1617    
1618    static int endswith(const char *s, char c)
1619    {
1620     int slen;
1621    
1622     if (!s || !s[0])
1623     return 0;
1624     slen = strlen(s) - 1;
1625    
1626     return s[slen] == c;
1627    }
1628    
1629  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1630    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1631      struct singleLine * line;      struct singleLine * line;
# Line 1344  int suitableImage(struct singleEntry * e Line 1635  int suitableImage(struct singleEntry * e
1635      char * rootspec;      char * rootspec;
1636      char * rootdev;      char * rootdev;
1637    
1638      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) {
1639     notSuitablePrintf(entry, 0, "marked to skip\n");
1640     return 0;
1641        }
1642    
1643      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1644      if (!line || line->numElements < 2) return 0;      if (!line) {
1645     notSuitablePrintf(entry, 0, "no line found\n");
1646     return 0;
1647        }
1648        if (line->numElements < 2) {
1649     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1650        line->numElements);
1651     return 0;
1652        }
1653    
1654      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1655        notSuitablePrintf(entry, 1, "\n");
1656        return 1;
1657        }
1658    
1659      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1660        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1661      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1662      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1663              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));      int hasslash = endswith(bootPrefix, '/') ||
1664      if (access(fullName, R_OK)) return 0;       beginswith(line->elements[1].item + rootspec_offset, '/');
1665        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1666                line->elements[1].item + rootspec_offset);
1667        if (access(fullName, R_OK)) {
1668     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1669     return 0;
1670        }
1671      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1672   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1673      if (i < line->numElements) {      if (i < line->numElements) {
# Line 1375  int suitableImage(struct singleEntry * e Line 1685  int suitableImage(struct singleEntry * e
1685      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1686    
1687              /* failed to find one */              /* failed to find one */
1688              if (!line) return 0;              if (!line) {
1689     notSuitablePrintf(entry, 0, "no line found\n");
1690     return 0;
1691                }
1692    
1693      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1694          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1695      if (i < line->numElements)      if (i < line->numElements)
1696          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1697      else {      else {
1698     notSuitablePrintf(entry, 0, "no root= entry found\n");
1699   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1700          return 0;          return 0;
1701              }              }
# Line 1389  int suitableImage(struct singleEntry * e Line 1703  int suitableImage(struct singleEntry * e
1703      }      }
1704    
1705      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1706      if (!dev)      if (!getpathbyspec(dev)) {
1707            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1708          return 0;          return 0;
1709        } else
1710     dev = getpathbyspec(dev);
1711    
1712      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1713      if (!rootdev)      if (!rootdev) {
1714            notSuitablePrintf(entry, 0, "can't find root device\n");
1715   return 0;   return 0;
1716        }
1717    
1718      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1719            notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1720     getuuidbydev(rootdev), getuuidbydev(dev));
1721          free(rootdev);          free(rootdev);
1722          return 0;          return 0;
1723      }      }
1724    
1725      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1726            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1727     getuuidbydev(rootdev), getuuidbydev(dev));
1728   free(rootdev);   free(rootdev);
1729          return 0;          return 0;
1730      }      }
1731    
1732      free(rootdev);      free(rootdev);
1733        notSuitablePrintf(entry, 1, "\n");
1734    
1735      return 1;      return 1;
1736  }  }
# Line 1450  struct singleEntry * findEntryByPath(str Line 1774  struct singleEntry * findEntryByPath(str
1774   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1775   if (!entry) return NULL;   if (!entry) return NULL;
1776    
1777   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1778   if (!line) return NULL;   if (!line) return NULL;
1779    
1780   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1488  struct singleEntry * findEntryByPath(str Line 1812  struct singleEntry * findEntryByPath(str
1812    
1813   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1814      prefix = "";      prefix = "";
1815      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1816      kernel += 6;      kernel += 6;
1817   }   }
1818    
# Line 1499  struct singleEntry * findEntryByPath(str Line 1823  struct singleEntry * findEntryByPath(str
1823    
1824      /* check all the lines matching checkType */      /* check all the lines matching checkType */
1825      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
1826   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
1827       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
1828       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1829   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
1830        ct = checkType | LT_KERNEL_EFI;
1831     line = getLineByType(ct, line);
1832     if (!line)
1833        break;  /* not found in this entry */
1834    
1835   if (line && line->numElements >= 2) {   if (line && line->type != LT_MENUENTRY &&
1836     line->numElements >= 2) {
1837      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1838      if (!strcmp(line->elements[1].item +      if (!strcmp(line->elements[1].item +
1839   ((rootspec != NULL) ? strlen(rootspec) : 0),   ((rootspec != NULL) ? strlen(rootspec) : 0),
1840   kernel + strlen(prefix)))   kernel + strlen(prefix)))
1841   break;   break;
1842   }   }
1843     if(line->type == LT_MENUENTRY &&
1844     !strcmp(line->elements[1].item, kernel))
1845        break;
1846      }      }
1847    
1848      /* make sure this entry has a kernel identifier; this skips      /* make sure this entry has a kernel identifier; this skips
1849       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
1850       * unfortunate)       * unfortunate)
1851       */       */
1852      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1853   break; /* found 'im! */   break; /* found 'im! */
1854   }   }
1855    
# Line 1602  void markRemovedImage(struct grubConfig Line 1934  void markRemovedImage(struct grubConfig
1934        const char * prefix) {        const char * prefix) {
1935      struct singleEntry * entry;      struct singleEntry * entry;
1936    
1937      if (!image) return;      if (!image)
1938     return;
1939    
1940        /* check and see if we're removing the default image */
1941        if (isdigit(*image)) {
1942     entry = findEntryByPath(cfg, image, prefix, NULL);
1943     if(entry)
1944        entry->skip = 1;
1945     return;
1946        }
1947    
1948      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1949   entry->skip = 1;   entry->skip = 1;
# Line 1610  void markRemovedImage(struct grubConfig Line 1951  void markRemovedImage(struct grubConfig
1951    
1952  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1953       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1954       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1955      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1956      int i, j;      int i, j;
1957    
1958      if (newIsDefault) {      if (newIsDefault) {
1959   config->defaultImage = 0;   config->defaultImage = 0;
1960   return;   return;
1961        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1962     if (findEntryByIndex(config, index))
1963        config->defaultImage = index;
1964     else
1965        config->defaultImage = -1;
1966     return;
1967      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1968   i = 0;   i = 0;
1969   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1629  void setDefaultImage(struct grubConfig * Line 1976  void setDefaultImage(struct grubConfig *
1976    
1977      /* defaultImage now points to what we'd like to use, but before any order      /* defaultImage now points to what we'd like to use, but before any order
1978         changes */         changes */
1979      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1980     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1981        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1982        return;        return;
1983    
# Line 1690  void displayEntry(struct singleEntry * e Line 2038  void displayEntry(struct singleEntry * e
2038    
2039      printf("index=%d\n", index);      printf("index=%d\n", index);
2040    
2041      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
2042      if (!line) {      if (!line) {
2043          printf("non linux entry\n");          printf("non linux entry\n");
2044          return;          return;
2045      }      }
2046    
2047      printf("kernel=%s\n", line->elements[1].item);      if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2048     printf("kernel=%s\n", line->elements[1].item);
2049        else
2050     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2051    
2052      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2053   printf("args=\"");   printf("args=\"");
# Line 1752  void displayEntry(struct singleEntry * e Line 2103  void displayEntry(struct singleEntry * e
2103   printf("root=%s\n", s);   printf("root=%s\n", s);
2104      }      }
2105    
2106      line = getLineByType(LT_INITRD, entry->lines);      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
2107    
2108      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2109   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2110        printf("initrd=");
2111     else
2112        printf("initrd=%s", prefix);
2113    
2114   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2115      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2116   printf("\n");   printf("\n");
2117      }      }
2118    
2119        line = getLineByType(LT_TITLE, entry->lines);
2120        if (line) {
2121     printf("title=%s\n", line->elements[1].item);
2122        } else {
2123     char * title;
2124     line = getLineByType(LT_MENUENTRY, entry->lines);
2125     title = grub2ExtractTitle(line);
2126     if (title)
2127        printf("title=%s\n", title);
2128        }
2129    }
2130    
2131    int isSuseSystem(void) {
2132        const char * path;
2133        const static char default_path[] = "/etc/SuSE-release";
2134    
2135        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2136     path = default_path;
2137    
2138        if (!access(path, R_OK))
2139     return 1;
2140        return 0;
2141    }
2142    
2143    int isSuseGrubConf(const char * path) {
2144        FILE * grubConf;
2145        char * line = NULL;
2146        size_t len = 0, res = 0;
2147    
2148        grubConf = fopen(path, "r");
2149        if (!grubConf) {
2150            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2151     return 0;
2152        }
2153    
2154        while ((res = getline(&line, &len, grubConf)) != -1) {
2155     if (!strncmp(line, "setup", 5)) {
2156        fclose(grubConf);
2157        free(line);
2158        return 1;
2159     }
2160        }
2161    
2162        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2163          path);
2164    
2165        fclose(grubConf);
2166        free(line);
2167        return 0;
2168    }
2169    
2170    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2171        FILE * grubConf;
2172        char * line = NULL;
2173        size_t res = 0, len = 0;
2174    
2175        if (!path) return 1;
2176        if (!lbaPtr) return 1;
2177    
2178        grubConf = fopen(path, "r");
2179        if (!grubConf) return 1;
2180    
2181        while ((res = getline(&line, &len, grubConf)) != -1) {
2182     if (line[res - 1] == '\n')
2183        line[res - 1] = '\0';
2184     else if (len > res)
2185        line[res] = '\0';
2186     else {
2187        line = realloc(line, res + 1);
2188        line[res] = '\0';
2189     }
2190    
2191     if (!strncmp(line, "setup", 5)) {
2192        if (strstr(line, "--force-lba")) {
2193            *lbaPtr = 1;
2194        } else {
2195            *lbaPtr = 0;
2196        }
2197        dbgPrintf("lba: %i\n", *lbaPtr);
2198        break;
2199     }
2200        }
2201    
2202        free(line);
2203        fclose(grubConf);
2204        return 0;
2205    }
2206    
2207    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2208        FILE * grubConf;
2209        char * line = NULL;
2210        size_t res = 0, len = 0;
2211        char * lastParamPtr = NULL;
2212        char * secLastParamPtr = NULL;
2213        char installDeviceNumber = '\0';
2214        char * bounds = NULL;
2215    
2216        if (!path) return 1;
2217        if (!devicePtr) return 1;
2218    
2219        grubConf = fopen(path, "r");
2220        if (!grubConf) return 1;
2221    
2222        while ((res = getline(&line, &len, grubConf)) != -1) {
2223     if (strncmp(line, "setup", 5))
2224        continue;
2225    
2226     if (line[res - 1] == '\n')
2227        line[res - 1] = '\0';
2228     else if (len > res)
2229        line[res] = '\0';
2230     else {
2231        line = realloc(line, res + 1);
2232        line[res] = '\0';
2233     }
2234    
2235     lastParamPtr = bounds = line + res;
2236    
2237     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2238     while (!isspace(*lastParamPtr))
2239        lastParamPtr--;
2240     lastParamPtr++;
2241    
2242     secLastParamPtr = lastParamPtr - 2;
2243     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2244    
2245     if (lastParamPtr + 3 > bounds) {
2246        dbgPrintf("lastParamPtr going over boundary");
2247        fclose(grubConf);
2248        free(line);
2249        return 1;
2250     }
2251     if (!strncmp(lastParamPtr, "(hd", 3))
2252        lastParamPtr += 3;
2253     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2254    
2255     /*
2256     * Second last parameter will decide wether last parameter is
2257     * an IMAGE_DEVICE or INSTALL_DEVICE
2258     */
2259     while (!isspace(*secLastParamPtr))
2260        secLastParamPtr--;
2261     secLastParamPtr++;
2262    
2263     if (secLastParamPtr + 3 > bounds) {
2264        dbgPrintf("secLastParamPtr going over boundary");
2265        fclose(grubConf);
2266        free(line);
2267        return 1;
2268     }
2269     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2270     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2271        secLastParamPtr += 3;
2272        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2273        installDeviceNumber = *secLastParamPtr;
2274     } else {
2275        installDeviceNumber = *lastParamPtr;
2276     }
2277    
2278     *devicePtr = malloc(6);
2279     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2280     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2281     fclose(grubConf);
2282     free(line);
2283     return 0;
2284        }
2285    
2286        free(line);
2287        fclose(grubConf);
2288        return 1;
2289    }
2290    
2291    int grubGetBootFromDeviceMap(const char * device,
2292         char ** bootPtr) {
2293        FILE * deviceMap;
2294        char * line = NULL;
2295        size_t res = 0, len = 0;
2296        char * devicePtr;
2297        char * bounds = NULL;
2298        const char * path;
2299        const static char default_path[] = "/boot/grub/device.map";
2300    
2301        if (!device) return 1;
2302        if (!bootPtr) return 1;
2303    
2304        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2305     path = default_path;
2306    
2307        dbgPrintf("opening grub device.map file from: %s\n", path);
2308        deviceMap = fopen(path, "r");
2309        if (!deviceMap)
2310     return 1;
2311    
2312        while ((res = getline(&line, &len, deviceMap)) != -1) {
2313            if (!strncmp(line, "#", 1))
2314        continue;
2315    
2316     if (line[res - 1] == '\n')
2317        line[res - 1] = '\0';
2318     else if (len > res)
2319        line[res] = '\0';
2320     else {
2321        line = realloc(line, res + 1);
2322        line[res] = '\0';
2323     }
2324    
2325     devicePtr = line;
2326     bounds = line + res;
2327    
2328     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2329        devicePtr++;
2330     dbgPrintf("device: %s\n", devicePtr);
2331    
2332     if (!strncmp(devicePtr, device, strlen(device))) {
2333        devicePtr += strlen(device);
2334        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2335            devicePtr++;
2336    
2337        *bootPtr = strdup(devicePtr);
2338        break;
2339     }
2340        }
2341    
2342        free(line);
2343        fclose(deviceMap);
2344        return 0;
2345    }
2346    
2347    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2348        char * grubDevice;
2349    
2350        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2351     dbgPrintf("error looking for grub installation device\n");
2352        else
2353     dbgPrintf("grubby installation device: %s\n", grubDevice);
2354    
2355        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2356     dbgPrintf("error looking for grub boot device\n");
2357        else
2358     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2359    
2360        free(grubDevice);
2361        return 0;
2362    }
2363    
2364    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2365        /*
2366         * This SuSE grub configuration file at this location is not your average
2367         * grub configuration file, but instead the grub commands used to setup
2368         * grub on that system.
2369         */
2370        const char * path;
2371        const static char default_path[] = "/etc/grub.conf";
2372    
2373        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2374     path = default_path;
2375    
2376        if (!isSuseGrubConf(path)) return 1;
2377    
2378        if (lbaPtr) {
2379            *lbaPtr = 0;
2380            if (suseGrubConfGetLba(path, lbaPtr))
2381                return 1;
2382        }
2383    
2384        if (bootPtr) {
2385            *bootPtr = NULL;
2386            suseGrubConfGetBoot(path, bootPtr);
2387        }
2388    
2389        return 0;
2390  }  }
2391    
2392  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1810  int parseSysconfigGrub(int * lbaPtr, cha Line 2437  int parseSysconfigGrub(int * lbaPtr, cha
2437  }  }
2438    
2439  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2440      char * boot;      char * boot = NULL;
2441      int lba;      int lba;
2442    
2443      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2444   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2445   if (boot) printf("boot=%s\n", boot);      free(boot);
2446        return;
2447     }
2448        } else {
2449            if (parseSysconfigGrub(&lba, &boot)) {
2450        free(boot);
2451        return;
2452     }
2453        }
2454    
2455        if (lba) printf("lba\n");
2456        if (boot) {
2457     printf("boot=%s\n", boot);
2458     free(boot);
2459      }      }
2460  }  }
2461    
# Line 1864  struct singleLine * addLineTmpl(struct s Line 2504  struct singleLine * addLineTmpl(struct s
2504  {  {
2505      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2506    
2507        if (isEfi && cfi == &grub2ConfigType) {
2508     enum lineType_e old = newLine->type;
2509     newLine->type = preferredLineType(newLine->type, cfi);
2510     if (old != newLine->type)
2511        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2512        }
2513    
2514      if (val) {      if (val) {
2515   /* override the inherited value with our own.   /* override the inherited value with our own.
2516   * 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 1873  struct singleLine * addLineTmpl(struct s Line 2520  struct singleLine * addLineTmpl(struct s
2520   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2521    
2522   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2523   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)) {
2524      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2525      if (rootspec != NULL) {      if (rootspec != NULL) {
2526   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 1910  struct singleLine *  addLine(struct sing Line 2557  struct singleLine *  addLine(struct sing
2557      /* 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
2558       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2559       */       */
   
2560      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2561   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2562   tmpl.type = type;   tmpl.type = type;
# Line 2014  void removeLine(struct singleEntry * ent Line 2660  void removeLine(struct singleEntry * ent
2660      free(line);      free(line);
2661  }  }
2662    
 static int isquote(char q)  
 {  
     if (q == '\'' || q == '\"')  
  return 1;  
     return 0;  
 }  
   
2663  static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)  static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2664  {  {
2665      struct singleLine newLine = {      struct singleLine newLine = {
# Line 2251  int updateActualImage(struct grubConfig Line 2890  int updateActualImage(struct grubConfig
2890      firstElement = 2;      firstElement = 2;
2891    
2892   } else {   } else {
2893      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
2894      if (!line) {      if (!line) {
2895   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2896   continue;   continue;
# Line 2416  int updateInitrd(struct grubConfig * cfg Line 3055  int updateInitrd(struct grubConfig * cfg
3055      if (!image) return 0;      if (!image) return 0;
3056    
3057      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3058          kernelLine = getLineByType(LT_KERNEL, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3059          if (!kernelLine) continue;          if (!kernelLine) continue;
3060    
3061          line = getLineByType(LT_INITRD, entry->lines);          line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3062          if (line)          if (line)
3063              removeLine(entry, line);              removeLine(entry, line);
3064          if (prefix) {          if (prefix) {
# Line 2430  int updateInitrd(struct grubConfig * cfg Line 3069  int updateInitrd(struct grubConfig * cfg
3069   endLine = getLineByType(LT_ENTRY_END, entry->lines);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3070   if (endLine)   if (endLine)
3071      removeLine(entry, endLine);      removeLine(entry, endLine);
3072          line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);          line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3073     kernelLine->indent, initrd);
3074          if (!line)          if (!line)
3075      return 1;      return 1;
3076   if (endLine) {   if (endLine) {
# Line 2468  int checkDeviceBootloader(const char * d Line 3108  int checkDeviceBootloader(const char * d
3108      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3109   return 0;   return 0;
3110    
3111      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3112   offset = boot[2] + 2;   offset = boot[2] + 2;
3113      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3114   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3115      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3116   offset = boot[1] + 2;        offset = boot[1] + 2;
3117            /*
3118     * it looks like grub, when copying stage1 into the mbr, patches stage1
3119     * right after the JMP location, replacing other instructions such as
3120     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3121     * different bytes.
3122     */
3123          if ((bootSect[offset + 1] == NOOP_OPCODE)
3124      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3125     offset = offset + 3;
3126          }
3127      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3128   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3129      } else {      } else {
# Line 2626  int checkForGrub(struct grubConfig * con Line 3276  int checkForGrub(struct grubConfig * con
3276      int fd;      int fd;
3277      unsigned char bootSect[512];      unsigned char bootSect[512];
3278      char * boot;      char * boot;
3279        int onSuse = isSuseSystem();
3280    
3281      if (parseSysconfigGrub(NULL, &boot))  
3282   return 0;      if (onSuse) {
3283     if (parseSuseGrubConf(NULL, &boot))
3284        return 0;
3285        } else {
3286     if (parseSysconfigGrub(NULL, &boot))
3287        return 0;
3288        }
3289    
3290      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3291      if (!boot)      if (!boot)
# Line 2647  int checkForGrub(struct grubConfig * con Line 3304  int checkForGrub(struct grubConfig * con
3304      }      }
3305      close(fd);      close(fd);
3306    
3307        /* The more elaborate checks do not work on SuSE. The checks done
3308         * seem to be reasonble (at least for now), so just return success
3309         */
3310        if (onSuse)
3311     return 2;
3312    
3313      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3314  }  }
3315    
# Line 2680  int checkForExtLinux(struct grubConfig * Line 3343  int checkForExtLinux(struct grubConfig *
3343      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3344  }  }
3345    
3346    int checkForYaboot(struct grubConfig * config) {
3347        /*
3348         * This is a simplistic check that we consider good enough for own puporses
3349         *
3350         * If we were to properly check if yaboot is *installed* we'd need to:
3351         * 1) get the system boot device (LT_BOOT)
3352         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3353         *    the content on the boot device
3354         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3355         * 4) check again if binary and boot device contents match
3356         */
3357        if (!access("/etc/yaboot.conf", R_OK))
3358     return 2;
3359    
3360        return 1;
3361    }
3362    
3363    int checkForElilo(struct grubConfig * config) {
3364        if (!access("/etc/elilo.conf", R_OK))
3365     return 2;
3366    
3367        return 1;
3368    }
3369    
3370  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3371      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3372    
# Line 2694  static char * getRootSpecifier(char * st Line 3381  static char * getRootSpecifier(char * st
3381  static char * getInitrdVal(struct grubConfig * config,  static char * getInitrdVal(struct grubConfig * config,
3382     const char * prefix, struct singleLine *tmplLine,     const char * prefix, struct singleLine *tmplLine,
3383     const char * newKernelInitrd,     const char * newKernelInitrd,
3384     char ** extraInitrds, int extraInitrdCount)     const char ** extraInitrds, int extraInitrdCount)
3385  {  {
3386      char *initrdVal, *end;      char *initrdVal, *end;
3387      int i;      int i;
# Line 2739  static char * getInitrdVal(struct grubCo Line 3426  static char * getInitrdVal(struct grubCo
3426    
3427  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3428           const char * prefix,           const char * prefix,
3429   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3430   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3431   char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3432                   char * newMBKernel, char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs) {
3433      struct singleEntry * new;      struct singleEntry * new;
3434      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3435      int needs;      int needs;
# Line 2796  int addNewKernel(struct grubConfig * con Line 3483  int addNewKernel(struct grubConfig * con
3483      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3484      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3485    
3486      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
     tmplLine->numElements >= 2) {  
3487   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3488      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3489       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 2874  int addNewKernel(struct grubConfig * con Line 3560  int addNewKernel(struct grubConfig * con
3560      /* template is multi but new is not,      /* template is multi but new is not,
3561       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3562       */       */
3563      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3564      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3565      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3566   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3567     config->cfi)->key);
3568      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3569    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3570      config->cfi);
3571      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3572   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3573      char *initrdVal;      char *initrdVal;
3574      /* template is multi but new is not,      /* template is multi but new is not,
3575       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3576       */       */
3577      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3578      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3579      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3580   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3581     config->cfi)->key);
3582      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3583      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3584      free(initrdVal);      free(initrdVal);
3585      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3586   }   }
3587    
3588      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3589   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3590      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3591      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 2948  int addNewKernel(struct grubConfig * con Line 3636  int addNewKernel(struct grubConfig * con
3636   }   }
3637      } else if (tmplLine->type == LT_ECHO) {      } else if (tmplLine->type == LT_ECHO) {
3638      requote(tmplLine, config->cfi);      requote(tmplLine, config->cfi);
3639        static const char *prefix = "'Loading ";
3640      if (tmplLine->numElements > 1 &&      if (tmplLine->numElements > 1 &&
3641      strstr(tmplLine->elements[1].item, "'Loading Linux ")) {      strstr(tmplLine->elements[1].item, prefix) &&
3642   char *prefix = "'Loading ";      masterLine->next &&
3643        iskernel(masterLine->next->type)) {
3644   char *newTitle = malloc(strlen(prefix) +   char *newTitle = malloc(strlen(prefix) +
3645   strlen(newKernelTitle) + 2);   strlen(newKernelTitle) + 2);
3646    
# Line 2977  int addNewKernel(struct grubConfig * con Line 3667  int addNewKernel(struct grubConfig * con
3667   */   */
3668   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
3669      case LT_KERNEL:      case LT_KERNEL:
3670        case LT_KERNEL_EFI:
3671   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
3672      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
3673   } else {   } else {
3674      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
3675              preferredLineType(LT_KERNEL, config->cfi),
3676        config->primaryIndent,        config->primaryIndent,
3677        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
3678      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 3056  int addNewKernel(struct grubConfig * con Line 3748  int addNewKernel(struct grubConfig * con
3748      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
3749   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
3750    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3751        config->cfi)) ?        config->cfi))
3752    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
3753     : preferredLineType(LT_KERNEL, config->cfi),
3754    config->secondaryIndent,    config->secondaryIndent,
3755    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
3756   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 3073  int addNewKernel(struct grubConfig * con Line 3766  int addNewKernel(struct grubConfig * con
3766   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3767   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
3768    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3769        config->cfi)) ?        config->cfi))
3770    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
3771       : preferredLineType(LT_INITRD, config->cfi),
3772    config->secondaryIndent,    config->secondaryIndent,
3773    initrdVal);    initrdVal);
3774   free(initrdVal);   free(initrdVal);
# Line 3106  static void traceback(int signum) Line 3800  static void traceback(int signum)
3800      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
3801      size = backtrace(array, 40);      size = backtrace(array, 40);
3802    
3803      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
3804              (unsigned long)size);              (unsigned long)size);
3805      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
3806      exit(1);      exit(1);
# Line 3147  int main(int argc, const char ** argv) { Line 3841  int main(int argc, const char ** argv) {
3841      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3842      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3843      int displayDefault = 0;      int displayDefault = 0;
3844        int displayDefaultIndex = 0;
3845        int displayDefaultTitle = 0;
3846        int defaultIndex = -1;
3847      struct poptOption options[] = {      struct poptOption options[] = {
3848   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3849      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 3164  int main(int argc, const char ** argv) { Line 3861  int main(int argc, const char ** argv) {
3861   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3862      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3863      _("bootfs") },      _("bootfs") },
3864  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3865   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3866      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3867  #endif  #endif
3868   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3869      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 3177  int main(int argc, const char ** argv) { Line 3874  int main(int argc, const char ** argv) {
3874        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3875        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3876        "template"), NULL },        "template"), NULL },
3877     { "debug", 0, 0, &debug, 0,
3878        _("print debugging information for failures") },
3879   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3880      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3881     { "default-index", 0, 0, &displayDefaultIndex, 0,
3882        _("display the index of the default kernel") },
3883     { "default-title", 0, 0, &displayDefaultTitle, 0,
3884        _("display the title of the default kernel") },
3885   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3886      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3887     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
3888        _("force grub2 stanzas to use efi") },
3889   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3890      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
3891   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
# Line 3193  int main(int argc, const char ** argv) { Line 3898  int main(int argc, const char ** argv) {
3898   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3899      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3900   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3901      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
3902   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3903      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3904   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 3213  int main(int argc, const char ** argv) { Line 3918  int main(int argc, const char ** argv) {
3918   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3919      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3920        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3921     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3922        _("make the given entry index the default entry"),
3923        _("entry-index") },
3924   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3925      _("configure silo bootloader") },      _("configure silo bootloader") },
3926   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 3234  int main(int argc, const char ** argv) { Line 3942  int main(int argc, const char ** argv) {
3942    
3943      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
3944    
3945        int i = 0;
3946        for (int j = 1; j < argc; j++)
3947     i += strlen(argv[j]) + 1;
3948        saved_command_line = malloc(i);
3949        if (!saved_command_line) {
3950     fprintf(stderr, "grubby: %m\n");
3951     exit(1);
3952        }
3953        saved_command_line[0] = '\0';
3954        for (int j = 1; j < argc; j++) {
3955     strcat(saved_command_line, argv[j]);
3956     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
3957        }
3958    
3959      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3960      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3961    
# Line 3295  int main(int argc, const char ** argv) { Line 4017  int main(int argc, const char ** argv) {
4017      }      }
4018    
4019      if (!cfi) {      if (!cfi) {
4020            if (grub2FindConfig(&grub2ConfigType))
4021        cfi = &grub2ConfigType;
4022     else
4023        #ifdef __ia64__        #ifdef __ia64__
4024   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4025        #elif __powerpc__        #elif __powerpc__
4026   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4027        #elif __sparc__        #elif __sparc__
4028          cfi = &siloConfigType;              cfi = &siloConfigType;
4029        #elif __s390__        #elif __s390__
4030          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4031        #elif __s390x__        #elif __s390x__
4032          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4033        #else        #else
         if (grub2FindConfig(&grub2ConfigType))  
     cfi = &grub2ConfigType;  
  else  
4034      cfi = &grubConfigType;      cfi = &grubConfigType;
4035        #endif        #endif
4036      }      }
# Line 3321  int main(int argc, const char ** argv) { Line 4043  int main(int argc, const char ** argv) {
4043      }      }
4044    
4045      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4046    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4047    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4048        (defaultIndex >= 0))) {
4049   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4050    "specified option"));    "specified option"));
4051   return 1;   return 1;
# Line 3364  int main(int argc, const char ** argv) { Line 4087  int main(int argc, const char ** argv) {
4087   makeDefault = 1;   makeDefault = 1;
4088   defaultKernel = NULL;   defaultKernel = NULL;
4089      }      }
4090        else if (defaultKernel && (defaultIndex >= 0)) {
4091     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4092      "may not be used together\n"));
4093     return 1;
4094        }
4095    
4096      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4097   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
# Line 3372  int main(int argc, const char ** argv) { Line 4100  int main(int argc, const char ** argv) {
4100      }      }
4101    
4102      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4103   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4104          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4105     && (defaultIndex == -1)) {
4106   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4107   return 1;   return 1;
4108      }      }
# Line 3400  int main(int argc, const char ** argv) { Line 4129  int main(int argc, const char ** argv) {
4129      }      }
4130    
4131      if (bootloaderProbe) {      if (bootloaderProbe) {
4132   int lrc = 0, grc = 0, gr2c = 0, erc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4133   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4134    
4135   const char *grub2config = grub2FindConfig(&grub2ConfigType);   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4136   if (grub2config) {   if (grub2config) {
# Line 3429  int main(int argc, const char ** argv) { Line 4158  int main(int argc, const char ** argv) {
4158   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4159   }   }
4160    
4161     if (!access(eliloConfigType.defaultConfig, F_OK)) {
4162        econfig = readConfig(eliloConfigType.defaultConfig,
4163     &eliloConfigType);
4164        if (!econfig)
4165     erc = 1;
4166        else
4167     erc = checkForElilo(econfig);
4168     }
4169    
4170   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4171      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4172      if (!lconfig)      if (!lconfig)
4173   erc = 1;   extrc = 1;
4174      else      else
4175   erc = checkForExtLinux(lconfig);   extrc = checkForExtLinux(lconfig);
4176   }   }
4177    
4178   if (lrc == 1 || grc == 1 || gr2c == 1) return 1;  
4179     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4180        yconfig = readConfig(yabootConfigType.defaultConfig,
4181     &yabootConfigType);
4182        if (!yconfig)
4183     yrc = 1;
4184        else
4185     yrc = checkForYaboot(yconfig);
4186     }
4187    
4188     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4189     erc == 1)
4190        return 1;
4191    
4192   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4193   if (gr2c == 2) printf("grub2\n");   if (gr2c == 2) printf("grub2\n");
4194   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4195   if (erc == 2) printf("extlinux\n");   if (extrc == 2) printf("extlinux\n");
4196     if (yrc == 2) printf("yaboot\n");
4197     if (erc == 2) printf("elilo\n");
4198    
4199   return 0;   return 0;
4200      }      }
4201    
4202        if (grubConfig == NULL) {
4203     printf("Could not find bootloader configuration file.\n");
4204     exit(1);
4205        }
4206    
4207      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4208      if (!config) return 1;      if (!config) return 1;
4209    
# Line 3460  int main(int argc, const char ** argv) { Line 4217  int main(int argc, const char ** argv) {
4217   if (!entry) return 0;   if (!entry) return 0;
4218   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4219    
4220   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
4221   if (!line) return 0;   if (!line) return 0;
4222    
4223          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 3468  int main(int argc, const char ** argv) { Line 4225  int main(int argc, const char ** argv) {
4225                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4226    
4227   return 0;   return 0;
4228    
4229        } else if (displayDefaultTitle) {
4230     struct singleLine * line;
4231     struct singleEntry * entry;
4232    
4233     if (config->defaultImage == -1) return 0;
4234     entry = findEntryByIndex(config, config->defaultImage);
4235     if (!entry) return 0;
4236    
4237     if (!configureGrub2) {
4238      line = getLineByType(LT_TITLE, entry->lines);
4239      if (!line) return 0;
4240      printf("%s\n", line->elements[1].item);
4241    
4242     } else {
4243      char * title;
4244    
4245      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4246      line = getLineByType(LT_MENUENTRY, entry->lines);
4247      if (!line) return 0;
4248      title = grub2ExtractTitle(line);
4249      if (title)
4250        printf("%s\n", title);
4251     }
4252     return 0;
4253    
4254        } else if (displayDefaultIndex) {
4255            if (config->defaultImage == -1) return 0;
4256            printf("%i\n", config->defaultImage);
4257            return 0;
4258    
4259      } else if (kernelInfo)      } else if (kernelInfo)
4260   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4261    
# Line 3479  int main(int argc, const char ** argv) { Line 4267  int main(int argc, const char ** argv) {
4267      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4268      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4269      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4270      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4271      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4272      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4273                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
# Line 3489  int main(int argc, const char ** argv) { Line 4277  int main(int argc, const char ** argv) {
4277      }      }
4278      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4279                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4280                       extraInitrds, extraInitrdCount,                       (const char **)extraInitrds, extraInitrdCount,
4281                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4282            
4283    

Legend:
Removed from v.1717  
changed lines
  Added in v.2250