Magellan Linux

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

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

trunk/grubby/grubby.c revision 1717 by niro, Sat Feb 18 00:47:17 2012 UTC tags/grubby-8_32/grubby.c revision 2703 by niro, Wed Jul 16 10:52:43 2014 UTC
# Line 36  Line 36 
36  #include <signal.h>  #include <signal.h>
37  #include <blkid/blkid.h>  #include <blkid/blkid.h>
38    
39    #include "log.h"
40    
41  #ifndef DEBUG  #ifndef DEBUG
42  #define DEBUG 0  #define DEBUG 0
43  #endif  #endif
# Line 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    #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 77  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 106  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
135    #define DEFAULT_SAVED_GRUB2 -3
136    
137  struct keywordTypes {  struct keywordTypes {
138      char * key;      char * key;
# Line 122  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 142  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 158  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 199  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 213  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 236  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) {
386      int count = 0;
387    
388      for (int i = 0; i < line->numElements; i++) {
389        int indentSize = 0;
390    
391        count = count + strlen(line->elements[i].item);
392    
393        indentSize = strlen(line->elements[i].indent);
394        if (indentSize > 0)
395          count = count + indentSize;
396        else
397          /* be extra safe and add room for whitespaces */
398          count = count + 1;
399      }
400    
401      /* room for trailing terminator */
402      count = count + 1;
403    
404      return count;
405    }
406    
407    static int isquote(char q)
408    {
409        if (q == '\'' || q == '\"')
410     return 1;
411        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) {
423        char * current;
424        char * current_indent;
425        int current_len;
426        int current_indent_len;
427        int i;
428    
429        /* bail out if line does not start with menuentry */
430        if (strcmp(line->elements[0].item, "menuentry"))
431          return NULL;
432    
433        i = 1;
434        current = line->elements[i].item;
435        current_len = strlen(current);
436    
437        /* if second word is quoted, strip the quotes and return single word */
438        if (isquote(*current) && isquote(current[current_len - 1])) {
439     char *tmp;
440    
441     tmp = strdup(current);
442     *(tmp + current_len - 1) = '\0';
443     return ++tmp;
444        }
445    
446        /* if no quotes, return second word verbatim */
447        if (!isquote(*current))
448     return current;
449    
450        /* second element start with a quote, so we have to find the element
451         * whose last character is also quote (assuming it's the closing one) */
452        int resultMaxSize;
453        char * result;
454        
455        resultMaxSize = sizeOfSingleLine(line);
456        result = malloc(resultMaxSize);
457        snprintf(result, resultMaxSize, "%s", ++current);
458        
459        i++;
460        for (; i < line->numElements; ++i) {
461     current = line->elements[i].item;
462     current_len = strlen(current);
463     current_indent = line->elements[i].indent;
464     current_indent_len = strlen(current_indent);
465    
466     strncat(result, current_indent, current_indent_len);
467     if (!isquote(current[current_len-1])) {
468        strncat(result, current, current_len);
469     } else {
470        strncat(result, current, current_len - 1);
471        break;
472     }
473        }
474        return result;
475    }
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 = 0,      .defaultSupportSaved = 1,
484      .defaultIsVariable = 1,      .defaultIsVariable = 1,
485      .entryStart = LT_MENUENTRY,      .entryStart = LT_MENUENTRY,
486      .entryEnd = LT_ENTRY_END,      .entryEnd = LT_ENTRY_END,
# Line 392  struct configFileInfo ziplConfigType = { Line 632  struct configFileInfo ziplConfigType = {
632  struct configFileInfo extlinuxConfigType = {  struct configFileInfo extlinuxConfigType = {
633      .defaultConfig = "/boot/extlinux/extlinux.conf",      .defaultConfig = "/boot/extlinux/extlinux.conf",
634      .keywords = extlinuxKeywords,      .keywords = extlinuxKeywords,
635        .caseInsensitive = 1,
636      .entryStart = LT_TITLE,      .entryStart = LT_TITLE,
637      .needsBootPrefix = 1,      .needsBootPrefix = 1,
638      .maxTitleLength = 255,      .maxTitleLength = 255,
639      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
640        .defaultIsUnquoted = 1,
641  };  };
642    
643  struct grubConfig {  struct grubConfig {
# Line 416  struct singleEntry * findEntryByIndex(st Line 658  struct singleEntry * findEntryByIndex(st
658  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
659       const char * path, const char * prefix,       const char * path, const char * prefix,
660       int * index);       int * index);
661    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
662          int * index);
663  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
664  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
665  struct singleLine * lineDup(struct singleLine * line);  struct singleLine * lineDup(struct singleLine * line);
# Line 480  static char * sdupprintf(const char *for Line 724  static char * sdupprintf(const char *for
724      return buf;      return buf;
725  }  }
726    
727    static enum lineType_e preferredLineType(enum lineType_e type,
728     struct configFileInfo *cfi) {
729        if (isEfi && cfi == &grub2ConfigType) {
730     switch (type) {
731     case LT_KERNEL:
732        return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
733     case LT_INITRD:
734        return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
735     default:
736        return type;
737     }
738    #if defined(__i386__) || defined(__x86_64__)
739        } else if (cfi == &grub2ConfigType) {
740     switch (type) {
741     case LT_KERNEL:
742        return LT_KERNEL_16;
743     case LT_INITRD:
744        return LT_INITRD_16;
745     default:
746        return type;
747     }
748    #endif
749        }
750        return type;
751    }
752    
753  static struct keywordTypes * getKeywordByType(enum lineType_e type,  static struct keywordTypes * getKeywordByType(enum lineType_e type,
754        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
755      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
     for (kw = cfi->keywords; kw->key; kw++) {  
756   if (kw->type == type)   if (kw->type == type)
757      return kw;      return kw;
758      }      }
# Line 513  static char * getuuidbydev(char *device) Line 782  static char * getuuidbydev(char *device)
782    
783  static enum lineType_e getTypeByKeyword(char * keyword,  static enum lineType_e getTypeByKeyword(char * keyword,
784   struct configFileInfo * cfi) {   struct configFileInfo * cfi) {
785      struct keywordTypes * kw;      for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
786      for (kw = cfi->keywords; kw->key; kw++) {   if (cfi->caseInsensitive) {
787   if (!strcmp(keyword, kw->key))      if (!strcasecmp(keyword, kw->key))
788      return kw->type;                  return kw->type;
789     } else {
790        if (!strcmp(keyword, kw->key))
791            return kw->type;
792     }
793      }      }
794      return LT_UNKNOWN;      return LT_UNKNOWN;
795  }  }
# Line 555  static int isEntryStart(struct singleLin Line 828  static int isEntryStart(struct singleLin
828  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
829  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct singleLine * line) {
830      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it (leaks a byte) */
831      char * title;      char * title = NULL;
832      title = strdup(line->elements[0].item);      if (line->type == LT_TITLE) {
833      title++;   title = strdup(line->elements[0].item);
834      *(title + strlen(title) - 1) = '\0';   title++;
835     *(title + strlen(title) - 1) = '\0';
836        } else if (line->type == LT_MENUENTRY)
837     title = strdup(line->elements[1].item);
838        else
839     return NULL;
840      return title;      return title;
841  }  }
842    
# Line 601  static void lineInit(struct singleLine * Line 879  static void lineInit(struct singleLine *
879  }  }
880    
881  struct singleLine * lineDup(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
     int i;  
882      struct singleLine * newLine = malloc(sizeof(*newLine));      struct singleLine * newLine = malloc(sizeof(*newLine));
883    
884      newLine->indent = strdup(line->indent);      newLine->indent = strdup(line->indent);
# Line 611  struct singleLine * lineDup(struct singl Line 888  struct singleLine * lineDup(struct singl
888      newLine->elements = malloc(sizeof(*newLine->elements) *      newLine->elements = malloc(sizeof(*newLine->elements) *
889         newLine->numElements);         newLine->numElements);
890    
891      for (i = 0; i < newLine->numElements; i++) {      for (int i = 0; i < newLine->numElements; i++) {
892   newLine->elements[i].indent = strdup(line->elements[i].indent);   newLine->elements[i].indent = strdup(line->elements[i].indent);
893   newLine->elements[i].item = strdup(line->elements[i].item);   newLine->elements[i].item = strdup(line->elements[i].item);
894      }      }
# Line 620  struct singleLine * lineDup(struct singl Line 897  struct singleLine * lineDup(struct singl
897  }  }
898    
899  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
     int i;  
   
900      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
901    
902      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
903   free(line->elements[i].item);   free(line->elements[i].item);
904   free(line->elements[i].indent);   free(line->elements[i].indent);
905      }      }
# Line 635  static void lineFree(struct singleLine * Line 910  static void lineFree(struct singleLine *
910    
911  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
912       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
913      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
914    
915      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
916     /* Need to handle this, because we strip the quotes from
917     * menuentry when read it. */
918     if (line->type == LT_MENUENTRY && i == 1) {
919        if(!isquote(*line->elements[i].item))
920     fprintf(out, "\'%s\'", line->elements[i].item);
921        else
922     fprintf(out, "%s", line->elements[i].item);
923        fprintf(out, "%s", line->elements[i].indent);
924    
925        continue;
926     }
927    
928   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
929      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
930    
# Line 733  static int getNextLine(char ** bufPtr, s Line 1018  static int getNextLine(char ** bufPtr, s
1018      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
1019   char * fullLine;   char * fullLine;
1020   int len;   int len;
  int i;  
1021    
1022   len = strlen(line->indent);   len = strlen(line->indent);
1023   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
1024      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
1025     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
1026    
# Line 745  static int getNextLine(char ** bufPtr, s Line 1029  static int getNextLine(char ** bufPtr, s
1029   free(line->indent);   free(line->indent);
1030   line->indent = fullLine;   line->indent = fullLine;
1031    
1032   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
1033      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
1034      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
1035      free(line->elements[i].item);      free(line->elements[i].item);
# Line 764  static int getNextLine(char ** bufPtr, s Line 1048  static int getNextLine(char ** bufPtr, s
1048   * elements up more   * elements up more
1049   */   */
1050   if (!isspace(kw->separatorChar)) {   if (!isspace(kw->separatorChar)) {
     int i;  
1051      char indent[2] = "";      char indent[2] = "";
1052      indent[0] = kw->separatorChar;      indent[0] = kw->separatorChar;
1053      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1054   char *p;   char *p;
  int j;  
1055   int numNewElements;   int numNewElements;
1056    
1057   numNewElements = 0;   numNewElements = 0;
# Line 785  static int getNextLine(char ** bufPtr, s Line 1067  static int getNextLine(char ** bufPtr, s
1067      sizeof(*line->elements) * elementsAlloced);      sizeof(*line->elements) * elementsAlloced);
1068   }   }
1069    
1070   for (j = line->numElements; j > i; j--) {   for (int j = line->numElements; j > i; j--) {
1071   line->elements[j + numNewElements] = line->elements[j];   line->elements[j + numNewElements] = line->elements[j];
1072   }   }
1073   line->numElements += numNewElements;   line->numElements += numNewElements;
# Line 798  static int getNextLine(char ** bufPtr, s Line 1080  static int getNextLine(char ** bufPtr, s
1080   break;   break;
1081   }   }
1082    
1083   free(line->elements[i].indent);   line->elements[i + 1].indent = line->elements[i].indent;
1084   line->elements[i].indent = strdup(indent);   line->elements[i].indent = strdup(indent);
1085   *p++ = '\0';   *p++ = '\0';
1086   i++;   i++;
1087   line->elements[i].item = strdup(p);   line->elements[i].item = strdup(p);
  line->elements[i].indent = strdup("");  
  p = line->elements[i].item;  
1088   }   }
1089      }      }
1090   }   }
# Line 814  static int getNextLine(char ** bufPtr, s Line 1094  static int getNextLine(char ** bufPtr, s
1094      return 0;      return 0;
1095  }  }
1096    
1097    static int isnumber(const char *s)
1098    {
1099        int i;
1100        for (i = 0; s[i] != '\0'; i++)
1101     if (s[i] < '0' || s[i] > '9')
1102        return 0;
1103        return i;
1104    }
1105    
1106  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1107        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1108      int in;      int in;
# Line 825  static struct grubConfig * readConfig(co Line 1114  static struct grubConfig * readConfig(co
1114      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
1115      char * end;      char * end;
1116      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
1117      int i, len;      int len;
1118      char * buf;      char * buf;
1119    
1120      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1121            printf("Could not find bootloader configuration\n");
1122            exit(1);
1123        } else if (!strcmp(inName, "-")) {
1124   in = 0;   in = 0;
1125      } else {      } else {
1126   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 871  static struct grubConfig * readConfig(co Line 1163  static struct grubConfig * readConfig(co
1163      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1164   }   }
1165    
1166   if (isEntryStart(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1167      sawEntry = 1;      sawEntry = 1;
1168      if (!entry) {      if (!entry) {
1169   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 888  static struct grubConfig * readConfig(co Line 1180  static struct grubConfig * readConfig(co
1180   }   }
1181    
1182   if (line->type == LT_SET_VARIABLE) {   if (line->type == LT_SET_VARIABLE) {
     int i;  
1183      dbgPrintf("found 'set' command (%d elements): ", line->numElements);      dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1184      dbgPrintf("%s", line->indent);      dbgPrintf("%s", line->indent);
1185      for (i = 0; i < line->numElements; i++)      for (int i = 0; i < line->numElements; i++)
1186   dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);   dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1187      dbgPrintf("\n");      dbgPrintf("\n");
1188      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1189      if (kwType && line->numElements == 3 &&      if (kwType && line->numElements == 3 &&
1190      !strcmp(line->elements[1].item, kwType->key)) {      !strcmp(line->elements[1].item, kwType->key) &&
1191        !is_special_grub2_variable(line->elements[2].item)) {
1192   dbgPrintf("Line sets default config\n");   dbgPrintf("Line sets default config\n");
1193   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1194   defaultLine = line;   defaultLine = line;
1195      }      }
  } else if (line->type == LT_DEFAULT && line->numElements == 2) {  
     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;  
     defaultLine = line;  
1196    
1197          } else if (line->type == LT_KERNEL) {          } else if (iskernel(line->type)) {
1198      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1199       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1200       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1201       */       */
1202      if (entry->multiboot)      if (entry && entry->multiboot)
1203   line->type = LT_HYPER;   line->type = LT_HYPER;
1204    
1205          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 919  static struct grubConfig * readConfig(co Line 1208  static struct grubConfig * readConfig(co
1208       * This only applies to grub, but that's the only place we       * This only applies to grub, but that's the only place we
1209       * should find LT_MBMODULE lines anyway.       * should find LT_MBMODULE lines anyway.
1210       */       */
1211      struct singleLine * l;      for (struct singleLine *l = entry->lines; l; l = l->next) {
     for (l = entry->lines; l; l = l->next) {  
1212   if (l->type == LT_HYPER)   if (l->type == LT_HYPER)
1213      break;      break;
1214   else if (l->type == LT_KERNEL) {   else if (iskernel(l->type)) {
1215      l->type = LT_HYPER;      l->type = LT_HYPER;
1216      break;      break;
1217   }   }
# Line 937  static struct grubConfig * readConfig(co Line 1225  static struct grubConfig * readConfig(co
1225      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1226      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1227    
1228   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1229      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1230        /* make the title/default a single argument (undoing our parsing) */
1231      len = 0;      len = 0;
1232      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1233   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1234   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1235      }      }
1236      buf = malloc(len + 1);      buf = malloc(len + 1);
1237      *buf = '\0';      *buf = '\0';
1238    
1239      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1240   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1241   free(line->elements[i].item);   free(line->elements[i].item);
1242    
# Line 961  static struct grubConfig * readConfig(co Line 1250  static struct grubConfig * readConfig(co
1250      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1251      line->elements[1].item = buf;      line->elements[1].item = buf;
1252      line->numElements = 2;      line->numElements = 2;
1253     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1254        /* let --remove-kernel="TITLE=what" work */
1255        len = 0;
1256        char *extras;
1257        char *title;
1258    
1259        for (int i = 1; i < line->numElements; i++) {
1260     len += strlen(line->elements[i].item);
1261     len += strlen(line->elements[i].indent);
1262        }
1263        buf = malloc(len + 1);
1264        *buf = '\0';
1265    
1266        /* allocate mem for extra flags. */
1267        extras = malloc(len + 1);
1268        *extras = '\0';
1269    
1270        /* get title. */
1271        for (int i = 0; i < line->numElements; i++) {
1272     if (!strcmp(line->elements[i].item, "menuentry"))
1273        continue;
1274     if (isquote(*line->elements[i].item))
1275        title = line->elements[i].item + 1;
1276     else
1277        title = line->elements[i].item;
1278    
1279     len = strlen(title);
1280            if (isquote(title[len-1])) {
1281        strncat(buf, title,len-1);
1282        break;
1283     } else {
1284        strcat(buf, title);
1285        strcat(buf, line->elements[i].indent);
1286     }
1287        }
1288    
1289        /* get extras */
1290        int count = 0;
1291        for (int i = 0; i < line->numElements; i++) {
1292     if (count >= 2) {
1293        strcat(extras, line->elements[i].item);
1294        strcat(extras, line->elements[i].indent);
1295     }
1296    
1297     if (!strcmp(line->elements[i].item, "menuentry"))
1298        continue;
1299    
1300     /* count ' or ", there should be two in menuentry line. */
1301     if (isquote(*line->elements[i].item))
1302        count++;
1303    
1304     len = strlen(line->elements[i].item);
1305    
1306     if (isquote(line->elements[i].item[len -1]))
1307        count++;
1308    
1309     /* ok, we get the final ' or ", others are extras. */
1310                }
1311        line->elements[1].indent =
1312     line->elements[line->numElements - 2].indent;
1313        line->elements[1].item = buf;
1314        line->elements[2].indent =
1315     line->elements[line->numElements - 2].indent;
1316        line->elements[2].item = extras;
1317        line->numElements = 3;
1318   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1319      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1320         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 1323  static struct grubConfig * readConfig(co
1323      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1324   int last, len;   int last, len;
1325    
1326   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1327      memmove(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1328      strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1329    
1330   last = line->numElements - 1;   last = line->numElements - 1;
1331   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1332   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1333      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1334      }      }
1335   }   }
1336    
1337     if (line->type == LT_DEFAULT && line->numElements == 2) {
1338        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1339        defaultLine = line;
1340     }
1341    
1342   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1343     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1344     probably responsible for putting new images in the wrong     probably responsible for putting new images in the wrong
# Line 1035  static struct grubConfig * readConfig(co Line 1393  static struct grubConfig * readConfig(co
1393    
1394      dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");      dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1395      if (defaultLine) {      if (defaultLine) {
1396   if (cfi->defaultIsVariable) {          if (defaultLine->numElements > 2 &&
1397        cfi->defaultSupportSaved &&
1398        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1399     cfg->cfi->defaultIsSaved = 1;
1400     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1401     if (cfg->cfi->getEnv) {
1402        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1403        if (defTitle) {
1404     int index = 0;
1405     if (isnumber(defTitle)) {
1406        index = atoi(defTitle);
1407        entry = findEntryByIndex(cfg, index);
1408     } else {
1409        entry = findEntryByTitle(cfg, defTitle, &index);
1410     }
1411     if (entry)
1412        cfg->defaultImage = index;
1413        }
1414     }
1415     } else if (cfi->defaultIsVariable) {
1416      char *value = defaultLine->elements[2].item;      char *value = defaultLine->elements[2].item;
1417      while (*value && (*value == '"' || *value == '\'' ||      while (*value && (*value == '"' || *value == '\'' ||
1418      *value == ' ' || *value == '\t'))      *value == ' ' || *value == '\t'))
# Line 1052  static struct grubConfig * readConfig(co Line 1429  static struct grubConfig * readConfig(co
1429      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1430      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1431   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1432      i = 0;      int i = 0;
1433      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1434   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1435      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 1075  static struct grubConfig * readConfig(co Line 1452  static struct grubConfig * readConfig(co
1452          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1453      }      }
1454   }   }
1455        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1456     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1457     if (defTitle) {
1458        int index = 0;
1459        if (isnumber(defTitle)) {
1460     index = atoi(defTitle);
1461     entry = findEntryByIndex(cfg, index);
1462        } else {
1463     entry = findEntryByTitle(cfg, defTitle, &index);
1464        }
1465        if (entry)
1466     cfg->defaultImage = index;
1467     }
1468      } else {      } else {
1469          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1470      }      }
# Line 1092  static void writeDefault(FILE * out, cha Line 1482  static void writeDefault(FILE * out, cha
1482    
1483      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1484   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1485      else if (cfg->defaultImage > -1) {      else if (cfg->cfi->defaultIsSaved) {
1486     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1487     if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1488        char *title;
1489        entry = findEntryByIndex(cfg, cfg->defaultImage);
1490        line = getLineByType(LT_MENUENTRY, entry->lines);
1491        if (!line)
1492     line = getLineByType(LT_TITLE, entry->lines);
1493        if (line) {
1494     title = extractTitle(line);
1495     if (title)
1496        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1497        }
1498     }
1499        } else if (cfg->defaultImage > -1) {
1500   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1501      if (cfg->cfi->defaultIsVariable) {      if (cfg->cfi->defaultIsVariable) {
1502          fprintf(out, "%sset default=\"%d\"\n", indent,          fprintf(out, "%sset default=\"%d\"\n", indent,
# Line 1152  static int writeConfig(struct grubConfig Line 1556  static int writeConfig(struct grubConfig
1556    
1557      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1558         directory to the dir of the symlink */         directory to the dir of the symlink */
1559              rc = chdir(dirname(strdupa(outName)));      char *dir = strdupa(outName);
1560        rc = chdir(dirname(dir));
1561      do {      do {
1562   buf = alloca(len + 1);   buf = alloca(len + 1);
1563   rc = readlink(basename(outName), buf, len);   rc = readlink(basename(outName), buf, len);
# Line 1194  static int writeConfig(struct grubConfig Line 1599  static int writeConfig(struct grubConfig
1599      while (line) {      while (line) {
1600          if (line->type == LT_SET_VARIABLE && defaultKw &&          if (line->type == LT_SET_VARIABLE && defaultKw &&
1601   line->numElements == 3 &&   line->numElements == 3 &&
1602   !strcmp(line->elements[1].item, defaultKw->key)) {   !strcmp(line->elements[1].item, defaultKw->key) &&
1603     !is_special_grub2_variable(line->elements[2].item)) {
1604      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1605      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1606   } else if (line->type == LT_DEFAULT) {   } else if (line->type == LT_DEFAULT) {
# Line 1290  static char *findDiskForRoot() Line 1696  static char *findDiskForRoot()
1696      buf[rc] = '\0';      buf[rc] = '\0';
1697      chptr = buf;      chptr = buf;
1698    
1699        char *foundanswer = NULL;
1700    
1701      while (chptr && chptr != buf+rc) {      while (chptr && chptr != buf+rc) {
1702          devname = chptr;          devname = chptr;
1703    
# Line 1317  static char *findDiskForRoot() Line 1725  static char *findDiskForRoot()
1725           * for '/' obviously.           * for '/' obviously.
1726           */           */
1727          if (*(++chptr) == '/' && *(++chptr) == ' ') {          if (*(++chptr) == '/' && *(++chptr) == ' ') {
1728              /*              /* remember the last / entry in mtab */
1729               * 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);  
1730          }          }
1731    
1732          /* Next line */          /* Next line */
# Line 1332  static char *findDiskForRoot() Line 1735  static char *findDiskForRoot()
1735              chptr++;              chptr++;
1736      }      }
1737    
1738        /* Return the last / entry found */
1739        if (foundanswer) {
1740            chptr = strchr(foundanswer, ' ');
1741            *chptr = '\0';
1742            return strdup(foundanswer);
1743        }
1744    
1745      return NULL;      return NULL;
1746  }  }
1747    
1748    void printEntry(struct singleEntry * entry, FILE *f) {
1749        int i;
1750        struct singleLine * line;
1751    
1752        for (line = entry->lines; line; line = line->next) {
1753     log_message(f, "DBG: %s", line->indent);
1754     for (i = 0; i < line->numElements; i++) {
1755        /* Need to handle this, because we strip the quotes from
1756         * menuentry when read it. */
1757        if (line->type == LT_MENUENTRY && i == 1) {
1758     if(!isquote(*line->elements[i].item))
1759        log_message(f, "\'%s\'", line->elements[i].item);
1760     else
1761        log_message(f, "%s", line->elements[i].item);
1762     log_message(f, "%s", line->elements[i].indent);
1763    
1764     continue;
1765        }
1766        
1767        log_message(f, "%s%s",
1768        line->elements[i].item, line->elements[i].indent);
1769     }
1770     log_message(f, "\n");
1771        }
1772    }
1773    
1774    void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1775    {
1776        static int once;
1777        va_list argp, argq;
1778    
1779        va_start(argp, fmt);
1780    
1781        va_copy(argq, argp);
1782        if (!once) {
1783     log_time(NULL);
1784     log_message(NULL, "command line: %s\n", saved_command_line);
1785        }
1786        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1787        log_vmessage(NULL, fmt, argq);
1788    
1789        printEntry(entry, NULL);
1790        va_end(argq);
1791    
1792        if (!debug) {
1793     once = 1;
1794         va_end(argp);
1795     return;
1796        }
1797    
1798        if (okay) {
1799     va_end(argp);
1800     return;
1801        }
1802    
1803        if (!once)
1804     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1805        once = 1;
1806        fprintf(stderr, "DBG: Image entry failed: ");
1807        vfprintf(stderr, fmt, argp);
1808        printEntry(entry, stderr);
1809        va_end(argp);
1810    }
1811    
1812    #define beginswith(s, c) ((s) && (s)[0] == (c))
1813    
1814    static int endswith(const char *s, char c)
1815    {
1816     int slen;
1817    
1818     if (!s || !s[0])
1819     return 0;
1820     slen = strlen(s) - 1;
1821    
1822     return s[slen] == c;
1823    }
1824    
1825  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1826    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1827      struct singleLine * line;      struct singleLine * line;
# Line 1344  int suitableImage(struct singleEntry * e Line 1831  int suitableImage(struct singleEntry * e
1831      char * rootspec;      char * rootspec;
1832      char * rootdev;      char * rootdev;
1833    
1834      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) {
1835     notSuitablePrintf(entry, 0, "marked to skip\n");
1836     return 0;
1837        }
1838    
1839      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1840      if (!line || line->numElements < 2) return 0;      if (!line) {
1841     notSuitablePrintf(entry, 0, "no line found\n");
1842     return 0;
1843        }
1844        if (line->numElements < 2) {
1845     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1846        line->numElements);
1847     return 0;
1848        }
1849    
1850      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1851        notSuitablePrintf(entry, 1, "\n");
1852        return 1;
1853        }
1854    
1855      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1856        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1857      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1858      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1859              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));      int hasslash = endswith(bootPrefix, '/') ||
1860      if (access(fullName, R_OK)) return 0;       beginswith(line->elements[1].item + rootspec_offset, '/');
1861        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1862                line->elements[1].item + rootspec_offset);
1863        if (access(fullName, R_OK)) {
1864     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1865     return 0;
1866        }
1867      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1868   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1869      if (i < line->numElements) {      if (i < line->numElements) {
# Line 1375  int suitableImage(struct singleEntry * e Line 1881  int suitableImage(struct singleEntry * e
1881      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1882    
1883              /* failed to find one */              /* failed to find one */
1884              if (!line) return 0;              if (!line) {
1885     notSuitablePrintf(entry, 0, "no line found\n");
1886     return 0;
1887                }
1888    
1889      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1890          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1891      if (i < line->numElements)      if (i < line->numElements)
1892          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1893      else {      else {
1894     notSuitablePrintf(entry, 0, "no root= entry found\n");
1895   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1896          return 0;          return 0;
1897              }              }
# Line 1389  int suitableImage(struct singleEntry * e Line 1899  int suitableImage(struct singleEntry * e
1899      }      }
1900    
1901      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1902      if (!dev)      if (!getpathbyspec(dev)) {
1903            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1904          return 0;          return 0;
1905        } else
1906     dev = getpathbyspec(dev);
1907    
1908      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1909      if (!rootdev)      if (!rootdev) {
1910            notSuitablePrintf(entry, 0, "can't find root device\n");
1911   return 0;   return 0;
1912        }
1913    
1914      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1915            notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1916     getuuidbydev(rootdev), getuuidbydev(dev));
1917          free(rootdev);          free(rootdev);
1918          return 0;          return 0;
1919      }      }
1920    
1921      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1922            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1923     getuuidbydev(rootdev), getuuidbydev(dev));
1924   free(rootdev);   free(rootdev);
1925          return 0;          return 0;
1926      }      }
1927    
1928      free(rootdev);      free(rootdev);
1929        notSuitablePrintf(entry, 1, "\n");
1930    
1931      return 1;      return 1;
1932  }  }
# Line 1450  struct singleEntry * findEntryByPath(str Line 1970  struct singleEntry * findEntryByPath(str
1970   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1971   if (!entry) return NULL;   if (!entry) return NULL;
1972    
1973   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1974   if (!line) return NULL;   if (!line) return NULL;
1975    
1976   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1488  struct singleEntry * findEntryByPath(str Line 2008  struct singleEntry * findEntryByPath(str
2008    
2009   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
2010      prefix = "";      prefix = "";
2011      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
2012      kernel += 6;      kernel += 6;
2013   }   }
2014    
# Line 1499  struct singleEntry * findEntryByPath(str Line 2019  struct singleEntry * findEntryByPath(str
2019    
2020      /* check all the lines matching checkType */      /* check all the lines matching checkType */
2021      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2022   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?   enum lineType_e ct = checkType;
2023       LT_KERNEL|LT_MBMODULE|LT_HYPER :   if (entry->multiboot && checkType == LT_KERNEL)
2024       checkType, line);      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2025   if (!line) break;  /* not found in this entry */   else if (checkType & LT_KERNEL)
2026        ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2027     line = getLineByType(ct, line);
2028     if (!line)
2029        break;  /* not found in this entry */
2030    
2031   if (line && line->numElements >= 2) {   if (line && line->type != LT_MENUENTRY &&
2032     line->numElements >= 2) {
2033      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
2034      if (!strcmp(line->elements[1].item +      if (!strcmp(line->elements[1].item +
2035   ((rootspec != NULL) ? strlen(rootspec) : 0),   ((rootspec != NULL) ? strlen(rootspec) : 0),
2036   kernel + strlen(prefix)))   kernel + strlen(prefix)))
2037   break;   break;
2038   }   }
2039     if(line->type == LT_MENUENTRY &&
2040     !strcmp(line->elements[1].item, kernel))
2041        break;
2042      }      }
2043    
2044      /* make sure this entry has a kernel identifier; this skips      /* make sure this entry has a kernel identifier; this skips
2045       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2046       * unfortunate)       * unfortunate)
2047       */       */
2048      if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2049   break; /* found 'im! */   break; /* found 'im! */
2050   }   }
2051    
# Line 1527  struct singleEntry * findEntryByPath(str Line 2055  struct singleEntry * findEntryByPath(str
2055      return entry;      return entry;
2056  }  }
2057    
2058    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2059          int * index) {
2060        struct singleEntry * entry;
2061        struct singleLine * line;
2062        int i;
2063        char * newtitle;
2064    
2065        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2066     if (index && i < *index)
2067        continue;
2068     line = getLineByType(LT_TITLE, entry->lines);
2069     if (!line)
2070        line = getLineByType(LT_MENUENTRY, entry->lines);
2071     if (!line)
2072        continue;
2073     newtitle = grub2ExtractTitle(line);
2074     if (!newtitle)
2075        continue;
2076     if (!strcmp(title, newtitle))
2077        break;
2078        }
2079    
2080        if (!entry)
2081     return NULL;
2082    
2083        if (index)
2084     *index = i;
2085        return entry;
2086    }
2087    
2088  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2089      struct singleEntry * entry;      struct singleEntry * entry;
2090    
# Line 1549  struct singleEntry * findTemplate(struct Line 2107  struct singleEntry * findTemplate(struct
2107      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2108      int index;      int index;
2109    
2110      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2111     if (cfg->cfi->getEnv) {
2112        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2113        if (defTitle) {
2114     int index = 0;
2115     if (isnumber(defTitle)) {
2116        index = atoi(defTitle);
2117        entry = findEntryByIndex(cfg, index);
2118     } else {
2119        entry = findEntryByTitle(cfg, defTitle, &index);
2120     }
2121     if (entry)
2122        cfg->defaultImage = index;
2123        }
2124     }
2125        } else if (cfg->defaultImage > -1) {
2126   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2127   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2128      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1602  void markRemovedImage(struct grubConfig Line 2175  void markRemovedImage(struct grubConfig
2175        const char * prefix) {        const char * prefix) {
2176      struct singleEntry * entry;      struct singleEntry * entry;
2177    
2178      if (!image) return;      if (!image)
2179     return;
2180    
2181        /* check and see if we're removing the default image */
2182        if (isdigit(*image)) {
2183     entry = findEntryByPath(cfg, image, prefix, NULL);
2184     if(entry)
2185        entry->skip = 1;
2186     return;
2187        }
2188    
2189      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
2190   entry->skip = 1;   entry->skip = 1;
# Line 1610  void markRemovedImage(struct grubConfig Line 2192  void markRemovedImage(struct grubConfig
2192    
2193  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
2194       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
2195       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
2196      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
2197      int i, j;      int i, j;
2198    
2199      if (newIsDefault) {      if (newIsDefault) {
2200   config->defaultImage = 0;   config->defaultImage = 0;
2201   return;   return;
2202        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
2203     if (findEntryByIndex(config, index))
2204        config->defaultImage = index;
2205     else
2206        config->defaultImage = -1;
2207     return;
2208      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
2209   i = 0;   i = 0;
2210   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1629  void setDefaultImage(struct grubConfig * Line 2217  void setDefaultImage(struct grubConfig *
2217    
2218      /* 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
2219         changes */         changes */
2220      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
2221     (config->defaultImage == DEFAULT_SAVED_GRUB2))
2222        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
2223        return;        return;
2224    
# Line 1690  void displayEntry(struct singleEntry * e Line 2279  void displayEntry(struct singleEntry * e
2279    
2280      printf("index=%d\n", index);      printf("index=%d\n", index);
2281    
2282      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2283      if (!line) {      if (!line) {
2284          printf("non linux entry\n");          printf("non linux entry\n");
2285          return;          return;
2286      }      }
2287    
2288      printf("kernel=%s\n", line->elements[1].item);      if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2289     printf("kernel=%s\n", line->elements[1].item);
2290        else
2291     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2292    
2293      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2294   printf("args=\"");   printf("args=\"");
# Line 1752  void displayEntry(struct singleEntry * e Line 2344  void displayEntry(struct singleEntry * e
2344   printf("root=%s\n", s);   printf("root=%s\n", s);
2345      }      }
2346    
2347      line = getLineByType(LT_INITRD, entry->lines);      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2348    
2349      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2350   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2351        printf("initrd=");
2352     else
2353        printf("initrd=%s", prefix);
2354    
2355   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2356      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2357   printf("\n");   printf("\n");
2358      }      }
2359    
2360        line = getLineByType(LT_TITLE, entry->lines);
2361        if (line) {
2362     printf("title=%s\n", line->elements[1].item);
2363        } else {
2364     char * title;
2365     line = getLineByType(LT_MENUENTRY, entry->lines);
2366     title = grub2ExtractTitle(line);
2367     if (title)
2368        printf("title=%s\n", title);
2369        }
2370    }
2371    
2372    int isSuseSystem(void) {
2373        const char * path;
2374        const static char default_path[] = "/etc/SuSE-release";
2375    
2376        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2377     path = default_path;
2378    
2379        if (!access(path, R_OK))
2380     return 1;
2381        return 0;
2382    }
2383    
2384    int isSuseGrubConf(const char * path) {
2385        FILE * grubConf;
2386        char * line = NULL;
2387        size_t len = 0, res = 0;
2388    
2389        grubConf = fopen(path, "r");
2390        if (!grubConf) {
2391            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2392     return 0;
2393        }
2394    
2395        while ((res = getline(&line, &len, grubConf)) != -1) {
2396     if (!strncmp(line, "setup", 5)) {
2397        fclose(grubConf);
2398        free(line);
2399        return 1;
2400     }
2401        }
2402    
2403        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2404          path);
2405    
2406        fclose(grubConf);
2407        free(line);
2408        return 0;
2409    }
2410    
2411    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2412        FILE * grubConf;
2413        char * line = NULL;
2414        size_t res = 0, len = 0;
2415    
2416        if (!path) return 1;
2417        if (!lbaPtr) return 1;
2418    
2419        grubConf = fopen(path, "r");
2420        if (!grubConf) return 1;
2421    
2422        while ((res = getline(&line, &len, grubConf)) != -1) {
2423     if (line[res - 1] == '\n')
2424        line[res - 1] = '\0';
2425     else if (len > res)
2426        line[res] = '\0';
2427     else {
2428        line = realloc(line, res + 1);
2429        line[res] = '\0';
2430     }
2431    
2432     if (!strncmp(line, "setup", 5)) {
2433        if (strstr(line, "--force-lba")) {
2434            *lbaPtr = 1;
2435        } else {
2436            *lbaPtr = 0;
2437        }
2438        dbgPrintf("lba: %i\n", *lbaPtr);
2439        break;
2440     }
2441        }
2442    
2443        free(line);
2444        fclose(grubConf);
2445        return 0;
2446    }
2447    
2448    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2449        FILE * grubConf;
2450        char * line = NULL;
2451        size_t res = 0, len = 0;
2452        char * lastParamPtr = NULL;
2453        char * secLastParamPtr = NULL;
2454        char installDeviceNumber = '\0';
2455        char * bounds = NULL;
2456    
2457        if (!path) return 1;
2458        if (!devicePtr) return 1;
2459    
2460        grubConf = fopen(path, "r");
2461        if (!grubConf) return 1;
2462    
2463        while ((res = getline(&line, &len, grubConf)) != -1) {
2464     if (strncmp(line, "setup", 5))
2465        continue;
2466    
2467     if (line[res - 1] == '\n')
2468        line[res - 1] = '\0';
2469     else if (len > res)
2470        line[res] = '\0';
2471     else {
2472        line = realloc(line, res + 1);
2473        line[res] = '\0';
2474     }
2475    
2476     lastParamPtr = bounds = line + res;
2477    
2478     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2479     while (!isspace(*lastParamPtr))
2480        lastParamPtr--;
2481     lastParamPtr++;
2482    
2483     secLastParamPtr = lastParamPtr - 2;
2484     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2485    
2486     if (lastParamPtr + 3 > bounds) {
2487        dbgPrintf("lastParamPtr going over boundary");
2488        fclose(grubConf);
2489        free(line);
2490        return 1;
2491     }
2492     if (!strncmp(lastParamPtr, "(hd", 3))
2493        lastParamPtr += 3;
2494     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2495    
2496     /*
2497     * Second last parameter will decide wether last parameter is
2498     * an IMAGE_DEVICE or INSTALL_DEVICE
2499     */
2500     while (!isspace(*secLastParamPtr))
2501        secLastParamPtr--;
2502     secLastParamPtr++;
2503    
2504     if (secLastParamPtr + 3 > bounds) {
2505        dbgPrintf("secLastParamPtr going over boundary");
2506        fclose(grubConf);
2507        free(line);
2508        return 1;
2509     }
2510     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2511     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2512        secLastParamPtr += 3;
2513        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2514        installDeviceNumber = *secLastParamPtr;
2515     } else {
2516        installDeviceNumber = *lastParamPtr;
2517     }
2518    
2519     *devicePtr = malloc(6);
2520     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2521     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2522     fclose(grubConf);
2523     free(line);
2524     return 0;
2525        }
2526    
2527        free(line);
2528        fclose(grubConf);
2529        return 1;
2530    }
2531    
2532    int grubGetBootFromDeviceMap(const char * device,
2533         char ** bootPtr) {
2534        FILE * deviceMap;
2535        char * line = NULL;
2536        size_t res = 0, len = 0;
2537        char * devicePtr;
2538        char * bounds = NULL;
2539        const char * path;
2540        const static char default_path[] = "/boot/grub/device.map";
2541    
2542        if (!device) return 1;
2543        if (!bootPtr) return 1;
2544    
2545        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2546     path = default_path;
2547    
2548        dbgPrintf("opening grub device.map file from: %s\n", path);
2549        deviceMap = fopen(path, "r");
2550        if (!deviceMap)
2551     return 1;
2552    
2553        while ((res = getline(&line, &len, deviceMap)) != -1) {
2554            if (!strncmp(line, "#", 1))
2555        continue;
2556    
2557     if (line[res - 1] == '\n')
2558        line[res - 1] = '\0';
2559     else if (len > res)
2560        line[res] = '\0';
2561     else {
2562        line = realloc(line, res + 1);
2563        line[res] = '\0';
2564     }
2565    
2566     devicePtr = line;
2567     bounds = line + res;
2568    
2569     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2570        devicePtr++;
2571     dbgPrintf("device: %s\n", devicePtr);
2572    
2573     if (!strncmp(devicePtr, device, strlen(device))) {
2574        devicePtr += strlen(device);
2575        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2576            devicePtr++;
2577    
2578        *bootPtr = strdup(devicePtr);
2579        break;
2580     }
2581        }
2582    
2583        free(line);
2584        fclose(deviceMap);
2585        return 0;
2586    }
2587    
2588    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2589        char * grubDevice;
2590    
2591        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2592     dbgPrintf("error looking for grub installation device\n");
2593        else
2594     dbgPrintf("grubby installation device: %s\n", grubDevice);
2595    
2596        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2597     dbgPrintf("error looking for grub boot device\n");
2598        else
2599     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2600    
2601        free(grubDevice);
2602        return 0;
2603    }
2604    
2605    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2606        /*
2607         * This SuSE grub configuration file at this location is not your average
2608         * grub configuration file, but instead the grub commands used to setup
2609         * grub on that system.
2610         */
2611        const char * path;
2612        const static char default_path[] = "/etc/grub.conf";
2613    
2614        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2615     path = default_path;
2616    
2617        if (!isSuseGrubConf(path)) return 1;
2618    
2619        if (lbaPtr) {
2620            *lbaPtr = 0;
2621            if (suseGrubConfGetLba(path, lbaPtr))
2622                return 1;
2623        }
2624    
2625        if (bootPtr) {
2626            *bootPtr = NULL;
2627            suseGrubConfGetBoot(path, bootPtr);
2628        }
2629    
2630        return 0;
2631  }  }
2632    
2633  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1810  int parseSysconfigGrub(int * lbaPtr, cha Line 2678  int parseSysconfigGrub(int * lbaPtr, cha
2678  }  }
2679    
2680  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2681      char * boot;      char * boot = NULL;
2682      int lba;      int lba;
2683    
2684      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2685   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2686   if (boot) printf("boot=%s\n", boot);      free(boot);
2687        return;
2688     }
2689        } else {
2690            if (parseSysconfigGrub(&lba, &boot)) {
2691        free(boot);
2692        return;
2693     }
2694        }
2695    
2696        if (lba) printf("lba\n");
2697        if (boot) {
2698     printf("boot=%s\n", boot);
2699     free(boot);
2700      }      }
2701  }  }
2702    
# Line 1864  struct singleLine * addLineTmpl(struct s Line 2745  struct singleLine * addLineTmpl(struct s
2745  {  {
2746      struct singleLine * newLine = lineDup(tmplLine);      struct singleLine * newLine = lineDup(tmplLine);
2747    
2748        if (isEfi && cfi == &grub2ConfigType) {
2749     enum lineType_e old = newLine->type;
2750     newLine->type = preferredLineType(newLine->type, cfi);
2751     if (old != newLine->type)
2752        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2753        }
2754    
2755      if (val) {      if (val) {
2756   /* override the inherited value with our own.   /* override the inherited value with our own.
2757   * This is a little weak because it only applies to elements[1]   * This is a little weak because it only applies to elements[1]
# Line 1873  struct singleLine * addLineTmpl(struct s Line 2761  struct singleLine * addLineTmpl(struct s
2761   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2762    
2763   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2764   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2765      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2766      if (rootspec != NULL) {      if (rootspec != NULL) {
2767   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 1910  struct singleLine *  addLine(struct sing Line 2798  struct singleLine *  addLine(struct sing
2798      /* NB: This function shouldn't allocate items on the heap, rather on the      /* NB: This function shouldn't allocate items on the heap, rather on the
2799       * stack since it calls addLineTmpl which will make copies.       * stack since it calls addLineTmpl which will make copies.
2800       */       */
   
2801      if (type == LT_TITLE && cfi->titleBracketed) {      if (type == LT_TITLE && cfi->titleBracketed) {
2802   /* we're doing a bracketed title (zipl) */   /* we're doing a bracketed title (zipl) */
2803   tmpl.type = type;   tmpl.type = type;
# Line 2014  void removeLine(struct singleEntry * ent Line 2901  void removeLine(struct singleEntry * ent
2901      free(line);      free(line);
2902  }  }
2903    
 static int isquote(char q)  
 {  
     if (q == '\'' || q == '\"')  
  return 1;  
     return 0;  
 }  
   
2904  static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)  static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2905  {  {
2906      struct singleLine newLine = {      struct singleLine newLine = {
# Line 2251  int updateActualImage(struct grubConfig Line 3131  int updateActualImage(struct grubConfig
3131      firstElement = 2;      firstElement = 2;
3132    
3133   } else {   } else {
3134      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3135      if (!line) {      if (!line) {
3136   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3137   continue;   continue;
# Line 2407  int updateImage(struct grubConfig * cfg, Line 3287  int updateImage(struct grubConfig * cfg,
3287      return rc;      return rc;
3288  }  }
3289    
3290    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3291     const char * image, const char * prefix, const char * initrd) {
3292        struct singleEntry * entry;
3293        struct singleLine * line, * kernelLine, *endLine = NULL;
3294        int index = 0;
3295    
3296        if (!image) return 0;
3297    
3298        for (; (entry = findEntryByPath(cfg, newMBKernel, prefix, &index)); index++) {
3299            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3300            if (!kernelLine) continue;
3301    
3302            if (prefix) {
3303                int prefixLen = strlen(prefix);
3304                if (!strncmp(initrd, prefix, prefixLen))
3305                    initrd += prefixLen;
3306            }
3307     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3308     if (endLine)
3309        removeLine(entry, endLine);
3310            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3311     kernelLine->indent, initrd);
3312            if (!line)
3313        return 1;
3314     if (endLine) {
3315        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3316                if (!line)
3317     return 1;
3318     }
3319    
3320            break;
3321        }
3322    
3323        return 0;
3324    }
3325    
3326  int updateInitrd(struct grubConfig * cfg, const char * image,  int updateInitrd(struct grubConfig * cfg, const char * image,
3327                   const char * prefix, const char * initrd) {                   const char * prefix, const char * initrd) {
3328      struct singleEntry * entry;      struct singleEntry * entry;
# Line 2416  int updateInitrd(struct grubConfig * cfg Line 3332  int updateInitrd(struct grubConfig * cfg
3332      if (!image) return 0;      if (!image) return 0;
3333    
3334      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3335          kernelLine = getLineByType(LT_KERNEL, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3336          if (!kernelLine) continue;          if (!kernelLine) continue;
3337    
3338          line = getLineByType(LT_INITRD, entry->lines);          line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3339          if (line)          if (line)
3340              removeLine(entry, line);              removeLine(entry, line);
3341          if (prefix) {          if (prefix) {
# Line 2430  int updateInitrd(struct grubConfig * cfg Line 3346  int updateInitrd(struct grubConfig * cfg
3346   endLine = getLineByType(LT_ENTRY_END, entry->lines);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3347   if (endLine)   if (endLine)
3348      removeLine(entry, endLine);      removeLine(entry, endLine);
3349          line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);   enum lineType_e lt;
3350     switch(kernelLine->type) {
3351        case LT_KERNEL:
3352            lt = LT_INITRD;
3353     break;
3354        case LT_KERNEL_EFI:
3355            lt = LT_INITRD_EFI;
3356     break;
3357        case LT_KERNEL_16:
3358            lt = LT_INITRD_16;
3359     break;
3360        default:
3361            lt = preferredLineType(LT_INITRD, cfg->cfi);
3362     }
3363            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3364          if (!line)          if (!line)
3365      return 1;      return 1;
3366   if (endLine) {   if (endLine) {
# Line 2468  int checkDeviceBootloader(const char * d Line 3398  int checkDeviceBootloader(const char * d
3398      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3399   return 0;   return 0;
3400    
3401      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3402   offset = boot[2] + 2;   offset = boot[2] + 2;
3403      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3404   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3405      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3406   offset = boot[1] + 2;        offset = boot[1] + 2;
3407            /*
3408     * it looks like grub, when copying stage1 into the mbr, patches stage1
3409     * right after the JMP location, replacing other instructions such as
3410     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3411     * different bytes.
3412     */
3413          if ((bootSect[offset + 1] == NOOP_OPCODE)
3414      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3415     offset = offset + 3;
3416          }
3417      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3418   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3419      } else {      } else {
# Line 2626  int checkForGrub(struct grubConfig * con Line 3566  int checkForGrub(struct grubConfig * con
3566      int fd;      int fd;
3567      unsigned char bootSect[512];      unsigned char bootSect[512];
3568      char * boot;      char * boot;
3569        int onSuse = isSuseSystem();
3570    
3571      if (parseSysconfigGrub(NULL, &boot))  
3572   return 0;      if (onSuse) {
3573     if (parseSuseGrubConf(NULL, &boot))
3574        return 0;
3575        } else {
3576     if (parseSysconfigGrub(NULL, &boot))
3577        return 0;
3578        }
3579    
3580      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3581      if (!boot)      if (!boot)
# Line 2647  int checkForGrub(struct grubConfig * con Line 3594  int checkForGrub(struct grubConfig * con
3594      }      }
3595      close(fd);      close(fd);
3596    
3597        /* The more elaborate checks do not work on SuSE. The checks done
3598         * seem to be reasonble (at least for now), so just return success
3599         */
3600        if (onSuse)
3601     return 2;
3602    
3603      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3604  }  }
3605    
# Line 2680  int checkForExtLinux(struct grubConfig * Line 3633  int checkForExtLinux(struct grubConfig *
3633      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3634  }  }
3635    
3636    int checkForYaboot(struct grubConfig * config) {
3637        /*
3638         * This is a simplistic check that we consider good enough for own puporses
3639         *
3640         * If we were to properly check if yaboot is *installed* we'd need to:
3641         * 1) get the system boot device (LT_BOOT)
3642         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3643         *    the content on the boot device
3644         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3645         * 4) check again if binary and boot device contents match
3646         */
3647        if (!access("/etc/yaboot.conf", R_OK))
3648     return 2;
3649    
3650        return 1;
3651    }
3652    
3653    int checkForElilo(struct grubConfig * config) {
3654        if (!access("/etc/elilo.conf", R_OK))
3655     return 2;
3656    
3657        return 1;
3658    }
3659    
3660  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3661      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3662    
# Line 2694  static char * getRootSpecifier(char * st Line 3671  static char * getRootSpecifier(char * st
3671  static char * getInitrdVal(struct grubConfig * config,  static char * getInitrdVal(struct grubConfig * config,
3672     const char * prefix, struct singleLine *tmplLine,     const char * prefix, struct singleLine *tmplLine,
3673     const char * newKernelInitrd,     const char * newKernelInitrd,
3674     char ** extraInitrds, int extraInitrdCount)     const char ** extraInitrds, int extraInitrdCount)
3675  {  {
3676      char *initrdVal, *end;      char *initrdVal, *end;
3677      int i;      int i;
# Line 2739  static char * getInitrdVal(struct grubCo Line 3716  static char * getInitrdVal(struct grubCo
3716    
3717  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3718           const char * prefix,           const char * prefix,
3719   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3720   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3721   char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3722                   char * newMBKernel, char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3723     const char * newDevTreePath) {
3724      struct singleEntry * new;      struct singleEntry * new;
3725      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3726      int needs;      int needs;
# Line 2783  int addNewKernel(struct grubConfig * con Line 3761  int addNewKernel(struct grubConfig * con
3761          needs |= NEED_MB;          needs |= NEED_MB;
3762          new->multiboot = 1;          new->multiboot = 1;
3763      }      }
3764        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3765     needs |= NEED_DEVTREE;
3766    
3767      if (template) {      if (template) {
3768   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 2796  int addNewKernel(struct grubConfig * con Line 3776  int addNewKernel(struct grubConfig * con
3776      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3777      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3778    
3779      if (tmplLine->type == LT_KERNEL &&      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
     tmplLine->numElements >= 2) {  
3780   if (!template->multiboot && (needs & NEED_MB)) {   if (!template->multiboot && (needs & NEED_MB)) {
3781      /* it's not a multiboot template and this is the kernel      /* it's not a multiboot template and this is the kernel
3782       * line.  Try to be intelligent about inserting the       * line.  Try to be intelligent about inserting the
# Line 2874  int addNewKernel(struct grubConfig * con Line 3853  int addNewKernel(struct grubConfig * con
3853      /* template is multi but new is not,      /* template is multi but new is not,
3854       * insert the kernel in the first module slot       * insert the kernel in the first module slot
3855       */       */
3856      tmplLine->type = LT_KERNEL;      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3857      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3858      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3859   strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3860     config->cfi)->key);
3861      newLine = addLineTmpl(new, tmplLine, newLine,      newLine = addLineTmpl(new, tmplLine, newLine,
3862    newKernelPath + strlen(prefix), config->cfi);    newKernelPath + strlen(prefix),
3863      config->cfi);
3864      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
3865   } else if (needs & NEED_INITRD) {   } else if (needs & NEED_INITRD) {
3866      char *initrdVal;      char *initrdVal;
3867      /* template is multi but new is not,      /* template is multi but new is not,
3868       * insert the initrd in the second module slot       * insert the initrd in the second module slot
3869       */       */
3870      tmplLine->type = LT_INITRD;      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3871      free(tmplLine->elements[0].item);      free(tmplLine->elements[0].item);
3872      tmplLine->elements[0].item =      tmplLine->elements[0].item =
3873   strdup(getKeywordByType(LT_INITRD, config->cfi)->key);   strdup(getKeywordByType(tmplLine->type,
3874     config->cfi)->key);
3875      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3876      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3877      free(initrdVal);      free(initrdVal);
3878      needs &= ~NEED_INITRD;      needs &= ~NEED_INITRD;
3879   }   }
3880    
3881      } else if (tmplLine->type == LT_INITRD &&      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
        tmplLine->numElements >= 2) {  
3882   if (needs & NEED_INITRD &&   if (needs & NEED_INITRD &&
3883      new->multiboot && !template->multiboot &&      new->multiboot && !template->multiboot &&
3884      config->cfi->mbInitRdIsModule) {      config->cfi->mbInitRdIsModule) {
# Line 2948  int addNewKernel(struct grubConfig * con Line 3929  int addNewKernel(struct grubConfig * con
3929   }   }
3930      } else if (tmplLine->type == LT_ECHO) {      } else if (tmplLine->type == LT_ECHO) {
3931      requote(tmplLine, config->cfi);      requote(tmplLine, config->cfi);
3932        static const char *prefix = "'Loading ";
3933      if (tmplLine->numElements > 1 &&      if (tmplLine->numElements > 1 &&
3934      strstr(tmplLine->elements[1].item, "'Loading Linux ")) {      strstr(tmplLine->elements[1].item, prefix) &&
3935   char *prefix = "'Loading ";      masterLine->next &&
3936        iskernel(masterLine->next->type)) {
3937   char *newTitle = malloc(strlen(prefix) +   char *newTitle = malloc(strlen(prefix) +
3938   strlen(newKernelTitle) + 2);   strlen(newKernelTitle) + 2);
3939    
# Line 2965  int addNewKernel(struct grubConfig * con Line 3948  int addNewKernel(struct grubConfig * con
3948   newLine = addLineTmpl(new, tmplLine, newLine, NULL,   newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3949   config->cfi);   config->cfi);
3950      }      }
3951        } else if (tmplLine->type == LT_DEVTREE &&
3952           tmplLine->numElements == 2 && newDevTreePath) {
3953            newLine = addLineTmpl(new, tmplLine, newLine,
3954          newDevTreePath + strlen(prefix),
3955          config->cfi);
3956     needs &= ~NEED_DEVTREE;
3957        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
3958     const char *ndtp = newDevTreePath;
3959     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
3960        ndtp += strlen(prefix);
3961     newLine = addLine(new, config->cfi, LT_DEVTREE,
3962      config->secondaryIndent,
3963      ndtp);
3964     needs &= ~NEED_DEVTREE;
3965     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3966      } else {      } else {
3967   /* pass through other lines from the template */   /* pass through other lines from the template */
3968   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 2977  int addNewKernel(struct grubConfig * con Line 3975  int addNewKernel(struct grubConfig * con
3975   */   */
3976   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
3977      case LT_KERNEL:      case LT_KERNEL:
3978        case LT_KERNEL_EFI:
3979        case LT_KERNEL_16:
3980   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
3981      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
3982   } else {   } else {
3983      newLine = addLine(new, config->cfi, LT_KERNEL,      newLine = addLine(new, config->cfi,
3984              preferredLineType(LT_KERNEL, config->cfi),
3985        config->primaryIndent,        config->primaryIndent,
3986        newKernelPath + strlen(prefix));        newKernelPath + strlen(prefix));
3987      needs &= ~NEED_KERNEL;      needs &= ~NEED_KERNEL;
# Line 3056  int addNewKernel(struct grubConfig * con Line 4057  int addNewKernel(struct grubConfig * con
4057      if (needs & NEED_KERNEL) {      if (needs & NEED_KERNEL) {
4058   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4059    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4060        config->cfi)) ?        config->cfi))
4061    LT_MBMODULE : LT_KERNEL,     ? LT_MBMODULE
4062     : preferredLineType(LT_KERNEL, config->cfi),
4063    config->secondaryIndent,    config->secondaryIndent,
4064    newKernelPath + strlen(prefix));    newKernelPath + strlen(prefix));
4065   needs &= ~NEED_KERNEL;   needs &= ~NEED_KERNEL;
# Line 3073  int addNewKernel(struct grubConfig * con Line 4075  int addNewKernel(struct grubConfig * con
4075   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);   initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
4076   newLine = addLine(new, config->cfi,   newLine = addLine(new, config->cfi,
4077    (new->multiboot && getKeywordByType(LT_MBMODULE,    (new->multiboot && getKeywordByType(LT_MBMODULE,
4078        config->cfi)) ?        config->cfi))
4079    LT_MBMODULE : LT_INITRD,     ? LT_MBMODULE
4080       : preferredLineType(LT_INITRD, config->cfi),
4081    config->secondaryIndent,    config->secondaryIndent,
4082    initrdVal);    initrdVal);
4083   free(initrdVal);   free(initrdVal);
4084   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4085      }      }
4086        if (needs & NEED_DEVTREE) {
4087     newLine = addLine(new, config->cfi, LT_DEVTREE,
4088      config->secondaryIndent,
4089      newDevTreePath);
4090     needs &= ~NEED_DEVTREE;
4091        }
4092    
4093        /* NEEDS_END must be last on bootloaders that need it... */
4094      if (needs & NEED_END) {      if (needs & NEED_END) {
4095   newLine = addLine(new, config->cfi, LT_ENTRY_END,   newLine = addLine(new, config->cfi, LT_ENTRY_END,
4096   config->secondaryIndent, NULL);   config->secondaryIndent, NULL);
4097   needs &= ~NEED_END;   needs &= ~NEED_END;
4098      }      }
   
4099      if (needs) {      if (needs) {
4100   printf(_("grubby: needs=%d, aborting\n"), needs);   printf(_("grubby: needs=%d, aborting\n"), needs);
4101   abort();   abort();
# Line 3106  static void traceback(int signum) Line 4116  static void traceback(int signum)
4116      memset(array, '\0', sizeof (array));      memset(array, '\0', sizeof (array));
4117      size = backtrace(array, 40);      size = backtrace(array, 40);
4118    
4119      fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",      fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
4120              (unsigned long)size);              (unsigned long)size);
4121      backtrace_symbols_fd(array, size, STDERR_FILENO);      backtrace_symbols_fd(array, size, STDERR_FILENO);
4122      exit(1);      exit(1);
# Line 3131  int main(int argc, const char ** argv) { Line 4141  int main(int argc, const char ** argv) {
4141      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4142      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4143      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4144      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4145      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4146      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4147      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 3141  int main(int argc, const char ** argv) { Line 4151  int main(int argc, const char ** argv) {
4151      char * removeArgs = NULL;      char * removeArgs = NULL;
4152      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4153      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4154        char * envPath = NULL;
4155      const char * chptr = NULL;      const char * chptr = NULL;
4156      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4157      struct grubConfig * config;      struct grubConfig * config;
4158      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
4159      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
4160      int displayDefault = 0;      int displayDefault = 0;
4161        int displayDefaultIndex = 0;
4162        int displayDefaultTitle = 0;
4163        int defaultIndex = -1;
4164      struct poptOption options[] = {      struct poptOption options[] = {
4165   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
4166      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 3164  int main(int argc, const char ** argv) { Line 4178  int main(int argc, const char ** argv) {
4178   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
4179      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
4180      _("bootfs") },      _("bootfs") },
4181  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
4182   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
4183      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
4184  #endif  #endif
4185   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
4186      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 3177  int main(int argc, const char ** argv) { Line 4191  int main(int argc, const char ** argv) {
4191        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
4192        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
4193        "template"), NULL },        "template"), NULL },
4194     { "debug", 0, 0, &debug, 0,
4195        _("print debugging information for failures") },
4196   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
4197      _("display the path of the default kernel") },      _("display the path of the default kernel") },
4198     { "default-index", 0, 0, &displayDefaultIndex, 0,
4199        _("display the index of the default kernel") },
4200     { "default-title", 0, 0, &displayDefaultTitle, 0,
4201        _("display the title of the default kernel") },
4202     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4203        _("device tree file for new stanza"), _("dtb-path") },
4204   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4205      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4206     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4207        _("force grub2 stanzas to use efi") },
4208     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4209        _("path for environment data"),
4210        _("path") },
4211   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4212      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4213   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
# Line 3193  int main(int argc, const char ** argv) { Line 4220  int main(int argc, const char ** argv) {
4220   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
4221      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
4222   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',   { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
4223      _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },      _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
4224   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
4225      _("configure lilo bootloader") },      _("configure lilo bootloader") },
4226   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 3213  int main(int argc, const char ** argv) { Line 4240  int main(int argc, const char ** argv) {
4240   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
4241      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
4242        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
4243     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
4244        _("make the given entry index the default entry"),
4245        _("entry-index") },
4246   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
4247      _("configure silo bootloader") },      _("configure silo bootloader") },
4248   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 3234  int main(int argc, const char ** argv) { Line 4264  int main(int argc, const char ** argv) {
4264    
4265      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4266    
4267        int i = 0;
4268        for (int j = 1; j < argc; j++)
4269     i += strlen(argv[j]) + 1;
4270        saved_command_line = malloc(i);
4271        if (!saved_command_line) {
4272     fprintf(stderr, "grubby: %m\n");
4273     exit(1);
4274        }
4275        saved_command_line[0] = '\0';
4276        for (int j = 1; j < argc; j++) {
4277     strcat(saved_command_line, argv[j]);
4278     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4279        }
4280    
4281      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4282      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4283    
# Line 3277  int main(int argc, const char ** argv) { Line 4321  int main(int argc, const char ** argv) {
4321   return 1;   return 1;
4322      } else if (configureGrub2) {      } else if (configureGrub2) {
4323   cfi = &grub2ConfigType;   cfi = &grub2ConfigType;
4324     if (envPath)
4325        cfi->envFile = envPath;
4326      } else if (configureLilo) {      } else if (configureLilo) {
4327   cfi = &liloConfigType;   cfi = &liloConfigType;
4328      } else if (configureGrub) {      } else if (configureGrub) {
# Line 3295  int main(int argc, const char ** argv) { Line 4341  int main(int argc, const char ** argv) {
4341      }      }
4342    
4343      if (!cfi) {      if (!cfi) {
4344            if (grub2FindConfig(&grub2ConfigType))
4345        cfi = &grub2ConfigType;
4346     else
4347        #ifdef __ia64__        #ifdef __ia64__
4348   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4349        #elif __powerpc__        #elif __powerpc__
4350   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4351        #elif __sparc__        #elif __sparc__
4352          cfi = &siloConfigType;              cfi = &siloConfigType;
4353        #elif __s390__        #elif __s390__
4354          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4355        #elif __s390x__        #elif __s390x__
4356          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4357        #else        #else
         if (grub2FindConfig(&grub2ConfigType))  
     cfi = &grub2ConfigType;  
  else  
4358      cfi = &grubConfigType;      cfi = &grubConfigType;
4359        #endif        #endif
4360      }      }
# Line 3320  int main(int argc, const char ** argv) { Line 4366  int main(int argc, const char ** argv) {
4366      grubConfig = cfi->defaultConfig;      grubConfig = cfi->defaultConfig;
4367      }      }
4368    
4369      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4370    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4371    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4372        (defaultIndex >= 0))) {
4373   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4374    "specified option"));    "specified option"));
4375   return 1;   return 1;
4376      }      }
4377    
4378      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4379     removeKernelPath)) {     removeKernelPath)) {
4380   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4381    "be used when adding or removing kernels\n"));    "be used when adding or removing kernels\n"));
# Line 3364  int main(int argc, const char ** argv) { Line 4411  int main(int argc, const char ** argv) {
4411   makeDefault = 1;   makeDefault = 1;
4412   defaultKernel = NULL;   defaultKernel = NULL;
4413      }      }
4414        else if (defaultKernel && (defaultIndex >= 0)) {
4415     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4416      "may not be used together\n"));
4417     return 1;
4418        }
4419    
4420      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4421   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
# Line 3372  int main(int argc, const char ** argv) { Line 4424  int main(int argc, const char ** argv) {
4424      }      }
4425    
4426      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4427   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4428          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4429     && (defaultIndex == -1)) {
4430   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4431   return 1;   return 1;
4432      }      }
# Line 3400  int main(int argc, const char ** argv) { Line 4453  int main(int argc, const char ** argv) {
4453      }      }
4454    
4455      if (bootloaderProbe) {      if (bootloaderProbe) {
4456   int lrc = 0, grc = 0, gr2c = 0, erc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4457   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4458    
4459   const char *grub2config = grub2FindConfig(&grub2ConfigType);   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4460   if (grub2config) {   if (grub2config) {
# Line 3429  int main(int argc, const char ** argv) { Line 4482  int main(int argc, const char ** argv) {
4482   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4483   }   }
4484    
4485     if (!access(eliloConfigType.defaultConfig, F_OK)) {
4486        econfig = readConfig(eliloConfigType.defaultConfig,
4487     &eliloConfigType);
4488        if (!econfig)
4489     erc = 1;
4490        else
4491     erc = checkForElilo(econfig);
4492     }
4493    
4494   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4495      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);      lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4496      if (!lconfig)      if (!lconfig)
4497   erc = 1;   extrc = 1;
4498      else      else
4499   erc = checkForExtLinux(lconfig);   extrc = checkForExtLinux(lconfig);
4500   }   }
4501    
4502   if (lrc == 1 || grc == 1 || gr2c == 1) return 1;  
4503     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4504        yconfig = readConfig(yabootConfigType.defaultConfig,
4505     &yabootConfigType);
4506        if (!yconfig)
4507     yrc = 1;
4508        else
4509     yrc = checkForYaboot(yconfig);
4510     }
4511    
4512     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4513     erc == 1)
4514        return 1;
4515    
4516   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4517   if (gr2c == 2) printf("grub2\n");   if (gr2c == 2) printf("grub2\n");
4518   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4519   if (erc == 2) printf("extlinux\n");   if (extrc == 2) printf("extlinux\n");
4520     if (yrc == 2) printf("yaboot\n");
4521     if (erc == 2) printf("elilo\n");
4522    
4523   return 0;   return 0;
4524      }      }
4525    
4526        if (grubConfig == NULL) {
4527     printf("Could not find bootloader configuration file.\n");
4528     exit(1);
4529        }
4530    
4531      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4532      if (!config) return 1;      if (!config) return 1;
4533    
# Line 3456  int main(int argc, const char ** argv) { Line 4537  int main(int argc, const char ** argv) {
4537          char * rootspec;          char * rootspec;
4538    
4539   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4540     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4541     cfi->defaultIsSaved)
4542        config->defaultImage = 0;
4543   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4544   if (!entry) return 0;   if (!entry) return 0;
4545   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4546    
4547   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
4548   if (!line) return 0;   if (!line) return 0;
4549    
4550          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 3468  int main(int argc, const char ** argv) { Line 4552  int main(int argc, const char ** argv) {
4552                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4553    
4554   return 0;   return 0;
4555    
4556        } else if (displayDefaultTitle) {
4557     struct singleLine * line;
4558     struct singleEntry * entry;
4559    
4560     if (config->defaultImage == -1) return 0;
4561     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4562     cfi->defaultIsSaved)
4563        config->defaultImage = 0;
4564     entry = findEntryByIndex(config, config->defaultImage);
4565     if (!entry) return 0;
4566    
4567     if (!configureGrub2) {
4568      line = getLineByType(LT_TITLE, entry->lines);
4569      if (!line) return 0;
4570      printf("%s\n", line->elements[1].item);
4571    
4572     } else {
4573      char * title;
4574    
4575      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4576      line = getLineByType(LT_MENUENTRY, entry->lines);
4577      if (!line) return 0;
4578      title = grub2ExtractTitle(line);
4579      if (title)
4580        printf("%s\n", title);
4581     }
4582     return 0;
4583    
4584        } else if (displayDefaultIndex) {
4585            if (config->defaultImage == -1) return 0;
4586     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4587     cfi->defaultIsSaved)
4588        config->defaultImage = 0;
4589            printf("%i\n", config->defaultImage);
4590            return 0;
4591    
4592      } else if (kernelInfo)      } else if (kernelInfo)
4593   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4594    
# Line 3479  int main(int argc, const char ** argv) { Line 4600  int main(int argc, const char ** argv) {
4600      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4601      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4602      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4603      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4604      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4605      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4606                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4607      if (updateKernelPath && newKernelInitrd) {      if (updateKernelPath && newKernelInitrd) {
4608              if (updateInitrd(config, updateKernelPath, bootPrefix,      if (newMBKernel) {
4609                               newKernelInitrd)) return 1;      if (addMBInitrd(config, newMBKernel, updateKernelPath,
4610     bootPrefix, newKernelInitrd))
4611        return 1;
4612        } else {
4613        if (updateInitrd(config, updateKernelPath, bootPrefix,
4614     newKernelInitrd))
4615     return 1;
4616        }
4617      }      }
4618      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4619                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4620                       extraInitrds, extraInitrdCount,                       (const char **)extraInitrds, extraInitrdCount,
4621                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4622            
4623    
4624      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {

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