Magellan Linux

Diff of /trunk/grubby/grubby.c

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

revision 2058 by niro, Wed Feb 20 14:06:30 2013 UTC revision 2980 by niro, Thu Jun 30 10:26:25 2016 UTC
# Line 36  Line 36 
36  #include <signal.h>  #include <signal.h>
37  #include <blkid/blkid.h>  #include <blkid/blkid.h>
38    
39    #include "log.h"
40    
41  #ifndef DEBUG  #ifndef DEBUG
42  #define DEBUG 0  #define DEBUG 0
43  #endif  #endif
# Line 58  int debug = 0; /* Currently just for tem Line 60  int debug = 0; /* Currently just for tem
60    
61  int isEfi = 0;  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 86  enum lineType_e { Line 96  enum lineType_e {
96      LT_SET_VARIABLE = 1 << 19,      LT_SET_VARIABLE = 1 << 19,
97      LT_KERNEL_EFI   = 1 << 20,      LT_KERNEL_EFI   = 1 << 20,
98      LT_INITRD_EFI   = 1 << 21,      LT_INITRD_EFI   = 1 << 21,
99      LT_UNKNOWN      = 1 << 22,      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 115  struct singleEntry { Line 128  struct singleEntry {
128  #define NEED_ARGS    (1 << 3)  #define NEED_ARGS    (1 << 3)
129  #define NEED_MB      (1 << 4)  #define NEED_MB      (1 << 4)
130  #define NEED_END     (1 << 5)  #define NEED_END     (1 << 5)
131    #define NEED_DEVTREE (1 << 6)
132    
133  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
134  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 132  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;      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 153  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 172  const char *grubFindConfig(struct config Line 193  const char *grubFindConfig(struct config
193   "/boot/grub/grub.conf",   "/boot/grub/grub.conf",
194   "/boot/grub/menu.lst",   "/boot/grub/menu.lst",
195   "/etc/grub.conf",   "/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 configFileInfo grubConfigType = { Line 222  struct configFileInfo grubConfigType = {
222      .mbHyperFirst = 1,      .mbHyperFirst = 1,
223      .mbInitRdIsModule = 1,      .mbInitRdIsModule = 1,
224      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
225        .titlePosition = 1,
226  };  };
227    
228  struct keywordTypes grub2Keywords[] = {  struct keywordTypes grub2Keywords[] = {
# Line 211  struct keywordTypes grub2Keywords[] = { Line 235  struct keywordTypes grub2Keywords[] = {
235      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
236      { "linux",      LT_KERNEL,      ' ' },      { "linux",      LT_KERNEL,      ' ' },
237      { "linuxefi",   LT_KERNEL_EFI,  ' ' },      { "linuxefi",   LT_KERNEL_EFI,  ' ' },
238        { "linux16",    LT_KERNEL_16,   ' ' },
239      { "initrd",     LT_INITRD,      ' ', ' ' },      { "initrd",     LT_INITRD,      ' ', ' ' },
240      { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },      { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
241        { "initrd16",   LT_INITRD_16,   ' ', ' ' },
242      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
243      { "kernel",     LT_HYPER,       ' ' },      { "kernel",     LT_HYPER,       ' ' },
244        { "devicetree", LT_DEVTREE,  ' ' },
245      { NULL, 0, 0 },      { NULL, 0, 0 },
246  };  };
247    
# Line 226  const char *grub2FindConfig(struct confi Line 253  const char *grub2FindConfig(struct confi
253      };      };
254      static int i = -1;      static int i = -1;
255      static const char *grub_cfg = "/boot/grub/grub.cfg";      static const char *grub_cfg = "/boot/grub/grub.cfg";
256        int rc = -1;
257    
258      if (i == -1) {      if (i == -1) {
259   for (i = 0; configFiles[i] != NULL; i++) {   for (i = 0; configFiles[i] != NULL; i++) {
260      dbgPrintf("Checking \"%s\": ", configFiles[i]);      dbgPrintf("Checking \"%s\": ", configFiles[i]);
261      if (!access(configFiles[i], R_OK)) {      if ((rc = access(configFiles[i], R_OK))) {
262     if (errno == EACCES) {
263        printf("Unable to access bootloader configuration file "
264           "\"%s\": %m\n", configFiles[i]);
265        exit(1);
266     }
267     continue;
268        } else {
269   dbgPrintf("found\n");   dbgPrintf("found\n");
270   return configFiles[i];   return configFiles[i];
271      }      }
# Line 249  const char *grub2FindConfig(struct confi Line 284  const char *grub2FindConfig(struct confi
284      return configFiles[i];      return configFiles[i];
285  }  }
286    
287    /* kind of hacky.  It'll give the first 1024 bytes, ish. */
288    static char *grub2GetEnv(struct configFileInfo *info, char *name)
289    {
290        static char buf[1025];
291        char *s = NULL;
292        char *ret = NULL;
293        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
294        int rc = asprintf(&s, "grub-editenv %s list | grep '^%s='", envFile, name);
295    
296        if (rc < 0)
297     return NULL;
298    
299        FILE *f = popen(s, "r");
300        if (!f)
301     goto out;
302    
303        memset(buf, '\0', sizeof (buf));
304        ret = fgets(buf, 1024, f);
305        pclose(f);
306    
307        if (ret) {
308     ret += strlen(name) + 1;
309     ret[strlen(ret) - 1] = '\0';
310        }
311        dbgPrintf("grub2GetEnv(%s): %s\n", name, ret);
312    out:
313        free(s);
314        return ret;
315    }
316    
317    static int sPopCount(const char *s, const char *c)
318    {
319        int ret = 0;
320        if (!s)
321     return -1;
322        for (int i = 0; s[i] != '\0'; i++)
323     for (int j = 0; c[j] != '\0'; j++)
324        if (s[i] == c[j])
325     ret++;
326        return ret;
327    }
328    
329    static char *shellEscape(const char *s)
330    {
331        int l = strlen(s) + sPopCount(s, "'") * 2;
332    
333        char *ret = calloc(l+1, sizeof (*ret));
334        if (!ret)
335     return NULL;
336        for (int i = 0, j = 0; s[i] != '\0'; i++, j++) {
337     if (s[i] == '\'')
338        ret[j++] = '\\';
339     ret[j] = s[i];
340        }
341        return ret;
342    }
343    
344    static void unquote(char *s)
345    {
346        int l = strlen(s);
347    
348        if ((s[l-1] == '\'' && s[0] == '\'') || (s[l-1] == '"' && s[0] == '"')) {
349     memmove(s, s+1, l-2);
350     s[l-2] = '\0';
351        }
352    }
353    
354    static int grub2SetEnv(struct configFileInfo *info, char *name, char *value)
355    {
356        char *s = NULL;
357        int rc = 0;
358        char *envFile = info->envFile ? info->envFile : "/boot/grub/grubenv";
359    
360        unquote(value);
361        value = shellEscape(value);
362        if (!value)
363        return -1;
364    
365        rc = asprintf(&s, "grub-editenv %s set '%s=%s'", envFile, name, value);
366        free(value);
367        if (rc <0)
368     return -1;
369    
370        dbgPrintf("grub2SetEnv(%s): %s\n", name, s);
371        rc = system(s);
372        free(s);
373        return rc;
374    }
375    
376    /* this is a gigantic hack to avoid clobbering grub2 variables... */
377    static int is_special_grub2_variable(const char *name)
378    {
379        if (!strcmp(name,"\"${next_entry}\""))
380     return 1;
381        if (!strcmp(name,"\"${prev_saved_entry}\""))
382     return 1;
383        return 0;
384    }
385    
386  int sizeOfSingleLine(struct singleLine * line) {  int sizeOfSingleLine(struct singleLine * line) {
387    int count = 0;    int count = 0;
388    
# Line 279  static int isquote(char q) Line 413  static int isquote(char q)
413  }  }
414    
415  static int iskernel(enum lineType_e type) {  static int iskernel(enum lineType_e type) {
416      return (type == LT_KERNEL || type == LT_KERNEL_EFI);      return (type == LT_KERNEL || type == LT_KERNEL_EFI || type == LT_KERNEL_16);
417  }  }
418    
419  static int isinitrd(enum lineType_e type) {  static int isinitrd(enum lineType_e type) {
420      return (type == LT_INITRD || type == LT_INITRD_EFI);      return (type == LT_INITRD || type == LT_INITRD_EFI || type == LT_INITRD_16);
421  }  }
422    
423  char *grub2ExtractTitle(struct singleLine * line) {  char *grub2ExtractTitle(struct singleLine * line) {
# Line 343  char *grub2ExtractTitle(struct singleLin Line 477  char *grub2ExtractTitle(struct singleLin
477    
478  struct configFileInfo grub2ConfigType = {  struct configFileInfo grub2ConfigType = {
479      .findConfig = grub2FindConfig,      .findConfig = grub2FindConfig,
480        .getEnv = grub2GetEnv,
481        .setEnv = grub2SetEnv,
482      .keywords = grub2Keywords,      .keywords = grub2Keywords,
483      .defaultIsIndex = 1,      .defaultIsIndex = 1,
484      .defaultSupportSaved = 1,      .defaultSupportSaved = 1,
# Line 447  struct keywordTypes extlinuxKeywords[] = Line 583  struct keywordTypes extlinuxKeywords[] =
583      { "initrd",    LT_INITRD,      ' ', ',' },      { "initrd",    LT_INITRD,      ' ', ',' },
584      { "append",    LT_KERNELARGS,  ' ' },      { "append",    LT_KERNELARGS,  ' ' },
585      { "prompt",     LT_UNKNOWN,     ' ' },      { "prompt",     LT_UNKNOWN,     ' ' },
586        { "fdt",        LT_DEVTREE,     ' ' },
587        { "fdtdir",     LT_DEVTREE,     ' ' },
588      { NULL,    0, 0 },      { NULL,    0, 0 },
589  };  };
590  int useextlinuxmenu;  int useextlinuxmenu;
# Line 457  struct configFileInfo eliloConfigType = Line 595  struct configFileInfo eliloConfigType =
595      .needsBootPrefix = 1,      .needsBootPrefix = 1,
596      .argsInQuotes = 1,      .argsInQuotes = 1,
597      .mbConcatArgs = 1,      .mbConcatArgs = 1,
598        .titlePosition = 1,
599  };  };
600    
601  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
# Line 465  struct configFileInfo liloConfigType = { Line 604  struct configFileInfo liloConfigType = {
604      .entryStart = LT_KERNEL,      .entryStart = LT_KERNEL,
605      .argsInQuotes = 1,      .argsInQuotes = 1,
606      .maxTitleLength = 15,      .maxTitleLength = 15,
607        .titlePosition = 1,
608  };  };
609    
610  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
# Line 475  struct configFileInfo yabootConfigType = Line 615  struct configFileInfo yabootConfigType =
615      .argsInQuotes = 1,      .argsInQuotes = 1,
616      .maxTitleLength = 15,      .maxTitleLength = 15,
617      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
618        .titlePosition = 1,
619  };  };
620    
621  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
# Line 484  struct configFileInfo siloConfigType = { Line 625  struct configFileInfo siloConfigType = {
625      .needsBootPrefix = 1,      .needsBootPrefix = 1,
626      .argsInQuotes = 1,      .argsInQuotes = 1,
627      .maxTitleLength = 15,      .maxTitleLength = 15,
628        .titlePosition = 1,
629  };  };
630    
631  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
# Line 502  struct configFileInfo extlinuxConfigType Line 644  struct configFileInfo extlinuxConfigType
644      .needsBootPrefix = 1,      .needsBootPrefix = 1,
645      .maxTitleLength = 255,      .maxTitleLength = 255,
646      .mbAllowExtraInitRds = 1,      .mbAllowExtraInitRds = 1,
647        .defaultIsUnquoted = 1,
648        .titlePosition = 1,
649  };  };
650    
651  struct grubConfig {  struct grubConfig {
# Line 522  struct singleEntry * findEntryByIndex(st Line 666  struct singleEntry * findEntryByIndex(st
666  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
667       const char * path, const char * prefix,       const char * path, const char * prefix,
668       int * index);       int * index);
669    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
670          int * index);
671  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
672  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
673  struct singleLine * lineDup(struct singleLine * line);  struct singleLine * lineDup(struct singleLine * line);
# Line 591  static enum lineType_e preferredLineType Line 737  static enum lineType_e preferredLineType
737      if (isEfi && cfi == &grub2ConfigType) {      if (isEfi && cfi == &grub2ConfigType) {
738   switch (type) {   switch (type) {
739   case LT_KERNEL:   case LT_KERNEL:
740      return LT_KERNEL_EFI;      return isEfiOnly ? LT_KERNEL : LT_KERNEL_EFI;
741   case LT_INITRD:   case LT_INITRD:
742      return LT_INITRD_EFI;      return isEfiOnly ? LT_INITRD : LT_INITRD_EFI;
743   default:   default:
744      return type;      return type;
745   }   }
746    #if defined(__i386__) || defined(__x86_64__)
747        } else if (cfi == &grub2ConfigType) {
748     switch (type) {
749     case LT_KERNEL:
750        return LT_KERNEL_16;
751     case LT_INITRD:
752        return LT_INITRD_16;
753     default:
754        return type;
755     }
756    #endif
757      }      }
758      return type;      return type;
759  }  }
# Line 677  static int isEntryStart(struct singleLin Line 834  static int isEntryStart(struct singleLin
834  }  }
835    
836  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
837  static char * extractTitle(struct singleLine * line) {  static char * extractTitle(struct grubConfig *cfg, struct singleLine * line) {
838      /* bracketed title... let's extract it (leaks a byte) */      /* bracketed title... let's extract it */
839      char * title;      char * title = NULL;
840      title = strdup(line->elements[0].item);      if (cfg->cfi == &grub2ConfigType)
841      title++;   return grub2ExtractTitle(line);
842      *(title + strlen(title) - 1) = '\0';      if (line->type == LT_TITLE) {
843     char *tmp = line->elements[cfg->cfi->titlePosition].item;
844     if (cfg->cfi->titleBracketed) {
845        tmp++;
846        title = strdup(tmp);
847        *(title + strlen(title) - 1) = '\0';
848     } else {
849        title = strdup(tmp);
850     }
851        } else if (line->type == LT_MENUENTRY)
852     title = strdup(line->elements[1].item);
853        else
854     return NULL;
855      return title;      return title;
856  }  }
857    
# Line 940  static int getNextLine(char ** bufPtr, s Line 1109  static int getNextLine(char ** bufPtr, s
1109      return 0;      return 0;
1110  }  }
1111    
1112    static int isnumber(const char *s)
1113    {
1114        int i;
1115        for (i = 0; s[i] != '\0'; i++)
1116     if (s[i] < '0' || s[i] > '9')
1117        return 0;
1118        return i;
1119    }
1120    
1121  static struct grubConfig * readConfig(const char * inName,  static struct grubConfig * readConfig(const char * inName,
1122        struct configFileInfo * cfi) {        struct configFileInfo * cfi) {
1123      int in;      int in;
# Line 954  static struct grubConfig * readConfig(co Line 1132  static struct grubConfig * readConfig(co
1132      int len;      int len;
1133      char * buf;      char * buf;
1134    
1135      if (!strcmp(inName, "-")) {      if (inName == NULL) {
1136            printf("Could not find bootloader configuration\n");
1137            exit(1);
1138        } else if (!strcmp(inName, "-")) {
1139   in = 0;   in = 0;
1140      } else {      } else {
1141   if ((in = open(inName, O_RDONLY)) < 0) {   if ((in = open(inName, O_RDONLY)) < 0) {
# Line 1021  static struct grubConfig * readConfig(co Line 1202  static struct grubConfig * readConfig(co
1202      dbgPrintf("\n");      dbgPrintf("\n");
1203      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);      struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1204      if (kwType && line->numElements == 3 &&      if (kwType && line->numElements == 3 &&
1205      !strcmp(line->elements[1].item, kwType->key)) {      !strcmp(line->elements[1].item, kwType->key) &&
1206        !is_special_grub2_variable(line->elements[2].item)) {
1207   dbgPrintf("Line sets default config\n");   dbgPrintf("Line sets default config\n");
1208   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;   cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1209   defaultLine = line;   defaultLine = line;
1210      }      }
  } else if (line->type == LT_DEFAULT && line->numElements == 2) {  
     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;  
     defaultLine = line;  
1211    
1212          } else if (iskernel(line->type)) {          } else if (iskernel(line->type)) {
1213      /* if by some freak chance this is multiboot and the "module"      /* if by some freak chance this is multiboot and the "module"
1214       * lines came earlier in the template, make sure to use LT_HYPER       * lines came earlier in the template, make sure to use LT_HYPER
1215       * instead of LT_KERNEL now       * instead of LT_KERNEL now
1216       */       */
1217      if (entry->multiboot)      if (entry && entry->multiboot)
1218   line->type = LT_HYPER;   line->type = LT_HYPER;
1219    
1220          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
# Line 1061  static struct grubConfig * readConfig(co Line 1240  static struct grubConfig * readConfig(co
1240      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1241      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1242    
1243   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if ((line->type == LT_DEFAULT && cfi->defaultIsUnquoted) ||
1244      /* make the title a single argument (undoing our parsing) */                  (line->type == LT_TITLE && line->numElements > 1)) {
1245        /* make the title/default a single argument (undoing our parsing) */
1246      len = 0;      len = 0;
1247      for (int i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1248   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
# Line 1169  static struct grubConfig * readConfig(co Line 1349  static struct grubConfig * readConfig(co
1349      }      }
1350   }   }
1351    
1352     if (line->type == LT_DEFAULT && line->numElements == 2) {
1353        cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1354        defaultLine = line;
1355     }
1356    
1357   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
1358     top of the file, move it there. Old versions of grubby were     top of the file, move it there. Old versions of grubby were
1359     probably responsible for putting new images in the wrong     probably responsible for putting new images in the wrong
# Line 1226  static struct grubConfig * readConfig(co Line 1411  static struct grubConfig * readConfig(co
1411          if (defaultLine->numElements > 2 &&          if (defaultLine->numElements > 2 &&
1412      cfi->defaultSupportSaved &&      cfi->defaultSupportSaved &&
1413      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {      !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1414      cfg->defaultImage = DEFAULT_SAVED_GRUB2;   cfg->cfi->defaultIsSaved = 1;
1415     cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1416     if (cfg->cfi->getEnv) {
1417        char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1418        if (defTitle) {
1419     int index = 0;
1420     if (isnumber(defTitle)) {
1421        index = atoi(defTitle);
1422        entry = findEntryByIndex(cfg, index);
1423     } else {
1424        entry = findEntryByTitle(cfg, defTitle, &index);
1425     }
1426     if (entry)
1427        cfg->defaultImage = index;
1428        }
1429     }
1430   } else if (cfi->defaultIsVariable) {   } else if (cfi->defaultIsVariable) {
1431      char *value = defaultLine->elements[2].item;      char *value = defaultLine->elements[2].item;
1432      while (*value && (*value == '"' || *value == '\'' ||      while (*value && (*value == '"' || *value == '\'' ||
# Line 1255  static struct grubConfig * readConfig(co Line 1455  static struct grubConfig * readConfig(co
1455                                  line->elements[1].item)) break;                                  line->elements[1].item)) break;
1456                  } else if (line) {                  } else if (line) {
1457                      if (!strcmp(defaultLine->elements[1].item,                      if (!strcmp(defaultLine->elements[1].item,
1458                                  extractTitle(line))) break;                                  extractTitle(cfg, line))) break;
1459                  }                  }
1460   i++;   i++;
1461   entry = NULL;   entry = NULL;
# Line 1267  static struct grubConfig * readConfig(co Line 1467  static struct grubConfig * readConfig(co
1467          cfg->defaultImage = -1;          cfg->defaultImage = -1;
1468      }      }
1469   }   }
1470        } else if (cfg->cfi->defaultIsSaved && cfg->cfi->getEnv) {
1471     char *defTitle = cfi->getEnv(cfg->cfi, "saved_entry");
1472     if (defTitle) {
1473        int index = 0;
1474        if (isnumber(defTitle)) {
1475     index = atoi(defTitle);
1476     entry = findEntryByIndex(cfg, index);
1477        } else {
1478     entry = findEntryByTitle(cfg, defTitle, &index);
1479        }
1480        if (entry)
1481     cfg->defaultImage = index;
1482     }
1483      } else {      } else {
1484          cfg->defaultImage = 0;          cfg->defaultImage = 0;
1485      }      }
# Line 1284  static void writeDefault(FILE * out, cha Line 1497  static void writeDefault(FILE * out, cha
1497    
1498      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1499   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1500      else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)      else if (cfg->cfi->defaultIsSaved) {
1501   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);   fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1502      else if (cfg->defaultImage > -1) {   if (cfg->defaultImage >= 0 && cfg->cfi->setEnv) {
1503        char *title;
1504        entry = findEntryByIndex(cfg, cfg->defaultImage);
1505        line = getLineByType(LT_MENUENTRY, entry->lines);
1506        if (!line)
1507     line = getLineByType(LT_TITLE, entry->lines);
1508        if (line) {
1509     title = extractTitle(cfg, line);
1510     if (title)
1511        cfg->cfi->setEnv(cfg->cfi, "saved_entry", title);
1512        }
1513     }
1514        } else if (cfg->defaultImage > -1) {
1515   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1516      if (cfg->cfi->defaultIsVariable) {      if (cfg->cfi->defaultIsVariable) {
1517          fprintf(out, "%sset default=\"%d\"\n", indent,          fprintf(out, "%sset default=\"%d\"\n", indent,
# Line 1319  static void writeDefault(FILE * out, cha Line 1544  static void writeDefault(FILE * out, cha
1544              else if (line && (line->numElements == 1) &&              else if (line && (line->numElements == 1) &&
1545                       cfg->cfi->titleBracketed) {                       cfg->cfi->titleBracketed) {
1546   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
1547                          extractTitle(line));                          extractTitle(cfg, line));
1548              }              }
1549   }   }
1550      }      }
# Line 1389  static int writeConfig(struct grubConfig Line 1614  static int writeConfig(struct grubConfig
1614      while (line) {      while (line) {
1615          if (line->type == LT_SET_VARIABLE && defaultKw &&          if (line->type == LT_SET_VARIABLE && defaultKw &&
1616   line->numElements == 3 &&   line->numElements == 3 &&
1617   !strcmp(line->elements[1].item, defaultKw->key)) {   !strcmp(line->elements[1].item, defaultKw->key) &&
1618     !is_special_grub2_variable(line->elements[2].item)) {
1619      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1620      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1621   } else if (line->type == LT_DEFAULT) {   } else if (line->type == LT_DEFAULT) {
# Line 1534  static char *findDiskForRoot() Line 1760  static char *findDiskForRoot()
1760      return NULL;      return NULL;
1761  }  }
1762    
1763  void printEntry(struct singleEntry * entry) {  void printEntry(struct singleEntry * entry, FILE *f) {
1764      int i;      int i;
1765      struct singleLine * line;      struct singleLine * line;
1766    
1767      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
1768   fprintf(stderr, "DBG: %s", line->indent);   log_message(f, "DBG: %s", line->indent);
1769   for (i = 0; i < line->numElements; i++) {   for (i = 0; i < line->numElements; i++) {
1770      /* Need to handle this, because we strip the quotes from      /* Need to handle this, because we strip the quotes from
1771       * menuentry when read it. */       * menuentry when read it. */
1772      if (line->type == LT_MENUENTRY && i == 1) {      if (line->type == LT_MENUENTRY && i == 1) {
1773   if(!isquote(*line->elements[i].item))   if(!isquote(*line->elements[i].item))
1774      fprintf(stderr, "\'%s\'", line->elements[i].item);      log_message(f, "\'%s\'", line->elements[i].item);
1775   else   else
1776      fprintf(stderr, "%s", line->elements[i].item);      log_message(f, "%s", line->elements[i].item);
1777   fprintf(stderr, "%s", line->elements[i].indent);   log_message(f, "%s", line->elements[i].indent);
1778    
1779   continue;   continue;
1780      }      }
1781            
1782      fprintf(stderr, "%s%s",      log_message(f, "%s%s",
1783      line->elements[i].item, line->elements[i].indent);      line->elements[i].item, line->elements[i].indent);
1784   }   }
1785   fprintf(stderr, "\n");   log_message(f, "\n");
1786      }      }
1787  }  }
1788    
1789  void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1790  {  {
1791      va_list argp;      static int once;
1792        va_list argp, argq;
1793    
1794        va_start(argp, fmt);
1795    
1796        va_copy(argq, argp);
1797        if (!once) {
1798     log_time(NULL);
1799     log_message(NULL, "command line: %s\n", saved_command_line);
1800        }
1801        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1802        log_vmessage(NULL, fmt, argq);
1803    
1804        printEntry(entry, NULL);
1805        va_end(argq);
1806    
1807      if (!debug)      if (!debug) {
1808     once = 1;
1809         va_end(argp);
1810   return;   return;
1811        }
1812    
1813      va_start(argp, fmt);      if (okay) {
1814     va_end(argp);
1815     return;
1816        }
1817    
1818        if (!once)
1819     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1820        once = 1;
1821      fprintf(stderr, "DBG: Image entry failed: ");      fprintf(stderr, "DBG: Image entry failed: ");
1822      vfprintf(stderr, fmt, argp);      vfprintf(stderr, fmt, argp);
1823      printEntry(entry);      printEntry(entry, stderr);
1824      va_end(argp);      va_end(argp);
1825  }  }
1826    
# Line 1597  int suitableImage(struct singleEntry * e Line 1847  int suitableImage(struct singleEntry * e
1847      char * rootdev;      char * rootdev;
1848    
1849      if (skipRemoved && entry->skip) {      if (skipRemoved && entry->skip) {
1850   notSuitablePrintf(entry, "marked to skip\n");   notSuitablePrintf(entry, 0, "marked to skip\n");
1851   return 0;   return 0;
1852      }      }
1853    
1854      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1855      if (!line) {      if (!line) {
1856   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1857   return 0;   return 0;
1858      }      }
1859      if (line->numElements < 2) {      if (line->numElements < 2) {
1860   notSuitablePrintf(entry, "line has only %d elements\n",   notSuitablePrintf(entry, 0, "line has only %d elements\n",
1861      line->numElements);      line->numElements);
1862   return 0;   return 0;
1863      }      }
1864    
1865      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) {
1866        notSuitablePrintf(entry, 1, "\n");
1867        return 1;
1868        }
1869    
1870      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1871        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
# Line 1623  int suitableImage(struct singleEntry * e Line 1876  int suitableImage(struct singleEntry * e
1876      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1877              line->elements[1].item + rootspec_offset);              line->elements[1].item + rootspec_offset);
1878      if (access(fullName, R_OK)) {      if (access(fullName, R_OK)) {
1879   notSuitablePrintf(entry, "access to %s failed\n", fullName);   notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1880   return 0;   return 0;
1881      }      }
1882      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 1644  int suitableImage(struct singleEntry * e Line 1897  int suitableImage(struct singleEntry * e
1897    
1898              /* failed to find one */              /* failed to find one */
1899              if (!line) {              if (!line) {
1900   notSuitablePrintf(entry, "no line found\n");   notSuitablePrintf(entry, 0, "no line found\n");
1901   return 0;   return 0;
1902              }              }
1903    
# Line 1653  int suitableImage(struct singleEntry * e Line 1906  int suitableImage(struct singleEntry * e
1906      if (i < line->numElements)      if (i < line->numElements)
1907          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1908      else {      else {
1909   notSuitablePrintf(entry, "no root= entry found\n");   notSuitablePrintf(entry, 0, "no root= entry found\n");
1910   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1911          return 0;          return 0;
1912              }              }
# Line 1662  int suitableImage(struct singleEntry * e Line 1915  int suitableImage(struct singleEntry * e
1915    
1916      dev = getpathbyspec(dev);      dev = getpathbyspec(dev);
1917      if (!getpathbyspec(dev)) {      if (!getpathbyspec(dev)) {
1918          notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);          notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1919          return 0;          return 0;
1920      } else      } else
1921   dev = getpathbyspec(dev);   dev = getpathbyspec(dev);
1922    
1923      rootdev = findDiskForRoot();      rootdev = findDiskForRoot();
1924      if (!rootdev) {      if (!rootdev) {
1925          notSuitablePrintf(entry, "can't find root device\n");          notSuitablePrintf(entry, 0, "can't find root device\n");
1926   return 0;   return 0;
1927      }      }
1928    
1929      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1930          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1931   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1932          free(rootdev);          free(rootdev);
1933          return 0;          return 0;
1934      }      }
1935    
1936      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1937          notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",          notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1938   getuuidbydev(rootdev), getuuidbydev(dev));   getuuidbydev(rootdev), getuuidbydev(dev));
1939   free(rootdev);   free(rootdev);
1940          return 0;          return 0;
1941      }      }
1942    
1943      free(rootdev);      free(rootdev);
1944        notSuitablePrintf(entry, 1, "\n");
1945    
1946      return 1;      return 1;
1947  }  }
# Line 1721  struct singleEntry * findEntryByPath(str Line 1975  struct singleEntry * findEntryByPath(str
1975   }   }
1976    
1977   indexVars[i + 1] = -1;   indexVars[i + 1] = -1;
1978    
1979   i = 0;   i = 0;
1980   if (index) {   if (index) {
1981      while (i < *index) i++;      while (i < *index) {
1982      if (indexVars[i] == -1) return NULL;   i++;
1983     if (indexVars[i] == -1) return NULL;
1984        }
1985   }   }
1986    
1987   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1988   if (!entry) return NULL;   if (!entry) return NULL;
1989    
1990   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
1991   if (!line) return NULL;   if (!line) return NULL;
1992    
1993   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1782  struct singleEntry * findEntryByPath(str Line 2038  struct singleEntry * findEntryByPath(str
2038      for (line = entry->lines; line; line = line->next) {      for (line = entry->lines; line; line = line->next) {
2039   enum lineType_e ct = checkType;   enum lineType_e ct = checkType;
2040   if (entry->multiboot && checkType == LT_KERNEL)   if (entry->multiboot && checkType == LT_KERNEL)
2041      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER|LT_KERNEL_16;
2042   else if (checkType & LT_KERNEL)   else if (checkType & LT_KERNEL)
2043      ct = checkType | LT_KERNEL_EFI;      ct = checkType | LT_KERNEL_EFI | LT_KERNEL_16;
2044   line = getLineByType(ct, line);   line = getLineByType(ct, line);
2045   if (!line)   if (!line)
2046      break;  /* not found in this entry */      break;  /* not found in this entry */
# Line 1806  struct singleEntry * findEntryByPath(str Line 2062  struct singleEntry * findEntryByPath(str
2062       * non-Linux boot entries (could find netbsd etc, though, which is       * non-Linux boot entries (could find netbsd etc, though, which is
2063       * unfortunate)       * unfortunate)
2064       */       */
2065      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))      if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines))
2066   break; /* found 'im! */   break; /* found 'im! */
2067   }   }
2068    
# Line 1816  struct singleEntry * findEntryByPath(str Line 2072  struct singleEntry * findEntryByPath(str
2072      return entry;      return entry;
2073  }  }
2074    
2075    struct singleEntry * findEntryByTitle(struct grubConfig * cfg, char *title,
2076          int * index) {
2077        struct singleEntry * entry;
2078        struct singleLine * line;
2079        int i;
2080        char * newtitle;
2081    
2082        for (i = 0, entry = cfg->entries; entry; entry = entry->next, i++) {
2083     if (index && i < *index)
2084        continue;
2085     line = getLineByType(LT_TITLE, entry->lines);
2086     if (!line)
2087        line = getLineByType(LT_MENUENTRY, entry->lines);
2088     if (!line)
2089        continue;
2090     newtitle = grub2ExtractTitle(line);
2091     if (!newtitle)
2092        continue;
2093     if (!strcmp(title, newtitle))
2094        break;
2095        }
2096    
2097        if (!entry)
2098     return NULL;
2099    
2100        if (index)
2101     *index = i;
2102        return entry;
2103    }
2104    
2105  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index) {
2106      struct singleEntry * entry;      struct singleEntry * entry;
2107    
# Line 1838  struct singleEntry * findTemplate(struct Line 2124  struct singleEntry * findTemplate(struct
2124      struct singleEntry * entry, * entry2;      struct singleEntry * entry, * entry2;
2125      int index;      int index;
2126    
2127      if (cfg->defaultImage > -1) {      if (cfg->cfi->defaultIsSaved) {
2128     if (cfg->cfi->getEnv) {
2129        char *defTitle = cfg->cfi->getEnv(cfg->cfi, "saved_entry");
2130        if (defTitle) {
2131     int index = 0;
2132     if (isnumber(defTitle)) {
2133        index = atoi(defTitle);
2134        entry = findEntryByIndex(cfg, index);
2135     } else {
2136        entry = findEntryByTitle(cfg, defTitle, &index);
2137     }
2138     if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2139        cfg->defaultImage = index;
2140        if (indexPtr)
2141     *indexPtr = index;
2142        return entry;
2143     }
2144        }
2145     }
2146        } else if (cfg->defaultImage > -1) {
2147   entry = findEntryByIndex(cfg, cfg->defaultImage);   entry = findEntryByIndex(cfg, cfg->defaultImage);
2148   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {   if (entry && suitableImage(entry, prefix, skipRemoved, flags)) {
2149      if (indexPtr) *indexPtr = cfg->defaultImage;      if (indexPtr) *indexPtr = cfg->defaultImage;
# Line 1992  void displayEntry(struct singleEntry * e Line 2297  void displayEntry(struct singleEntry * e
2297      struct singleLine * line;      struct singleLine * line;
2298      char * root = NULL;      char * root = NULL;
2299      int i;      int i;
2300        int j;
2301    
2302      printf("index=%d\n", index);      printf("index=%d\n", index);
2303    
2304      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
2305      if (!line) {      if (!line) {
2306          printf("non linux entry\n");          printf("non linux entry\n");
2307          return;          return;
# Line 2060  void displayEntry(struct singleEntry * e Line 2366  void displayEntry(struct singleEntry * e
2366   printf("root=%s\n", s);   printf("root=%s\n", s);
2367      }      }
2368    
2369      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);      line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
2370    
2371      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2372   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
# Line 2079  void displayEntry(struct singleEntry * e Line 2385  void displayEntry(struct singleEntry * e
2385      } else {      } else {
2386   char * title;   char * title;
2387   line = getLineByType(LT_MENUENTRY, entry->lines);   line = getLineByType(LT_MENUENTRY, entry->lines);
2388   title = grub2ExtractTitle(line);   if (line) {
2389   if (title)      title = grub2ExtractTitle(line);
2390      printf("title=%s\n", title);      if (title)
2391     printf("title=%s\n", title);
2392     }
2393        }
2394    
2395        for (j = 0, line = entry->lines; line; line = line->next) {
2396     if ((line->type & LT_MBMODULE) && line->numElements >= 2) {
2397        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2398     printf("mbmodule%d=", j);
2399        else
2400     printf("mbmodule%d=%s", j, prefix);
2401    
2402        for (i = 1; i < line->numElements; i++)
2403     printf("%s%s", line->elements[i].item, line->elements[i].indent);
2404        printf("\n");
2405        j++;
2406     }
2407      }      }
2408  }  }
2409    
# Line 2477  struct singleLine * addLineTmpl(struct s Line 2799  struct singleLine * addLineTmpl(struct s
2799   insertElement(newLine, val, 1, cfi);   insertElement(newLine, val, 1, cfi);
2800    
2801   /* but try to keep the rootspec from the template... sigh */   /* but try to keep the rootspec from the template... sigh */
2802   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {   if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI|LT_KERNEL_16|LT_INITRD_16)) {
2803      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);      char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2804      if (rootspec != NULL) {      if (rootspec != NULL) {
2805   free(newLine->elements[1].item);   free(newLine->elements[1].item);
# Line 2847  int updateActualImage(struct grubConfig Line 3169  int updateActualImage(struct grubConfig
3169      firstElement = 2;      firstElement = 2;
3170    
3171   } else {   } else {
3172      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3173      if (!line) {      if (!line) {
3174   /* no LT_KERNEL or LT_MBMODULE in this entry? */   /* no LT_KERNEL or LT_MBMODULE in this entry? */
3175   continue;   continue;
# Line 3003  int updateImage(struct grubConfig * cfg, Line 3325  int updateImage(struct grubConfig * cfg,
3325      return rc;      return rc;
3326  }  }
3327    
3328    int addMBInitrd(struct grubConfig * cfg, const char *newMBKernel,
3329     const char * image, const char * prefix, const char * initrd,
3330     const char * title) {
3331        struct singleEntry * entry;
3332        struct singleLine * line, * kernelLine, *endLine = NULL;
3333        int index = 0;
3334    
3335        if (!image) return 0;
3336    
3337        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3338            kernelLine = getLineByType(LT_MBMODULE, entry->lines);
3339            if (!kernelLine) continue;
3340    
3341     /* if title is supplied, the entry's title must match it. */
3342     if (title) {
3343        char *linetitle;
3344    
3345        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3346        if (!line)
3347     continue;
3348    
3349        linetitle = extractTitle(cfg, line);
3350        if (!linetitle)
3351     continue;
3352        if (strcmp(title, linetitle)) {
3353     free(linetitle);
3354     continue;
3355        }
3356        free(linetitle);
3357     }
3358    
3359            if (prefix) {
3360                int prefixLen = strlen(prefix);
3361                if (!strncmp(initrd, prefix, prefixLen))
3362                    initrd += prefixLen;
3363            }
3364     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3365     if (endLine)
3366        removeLine(entry, endLine);
3367            line = addLine(entry, cfg->cfi, preferredLineType(LT_MBMODULE,cfg->cfi),
3368     kernelLine->indent, initrd);
3369            if (!line)
3370        return 1;
3371     if (endLine) {
3372        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3373                if (!line)
3374     return 1;
3375     }
3376    
3377            break;
3378        }
3379    
3380        return 0;
3381    }
3382    
3383  int updateInitrd(struct grubConfig * cfg, const char * image,  int updateInitrd(struct grubConfig * cfg, const char * image,
3384                   const char * prefix, const char * initrd) {                   const char * prefix, const char * initrd, const char * title) {
3385      struct singleEntry * entry;      struct singleEntry * entry;
3386      struct singleLine * line, * kernelLine, *endLine = NULL;      struct singleLine * line, * kernelLine, *endLine = NULL;
3387      int index = 0;      int index = 0;
# Line 3012  int updateInitrd(struct grubConfig * cfg Line 3389  int updateInitrd(struct grubConfig * cfg
3389      if (!image) return 0;      if (!image) return 0;
3390    
3391      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3392          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);          kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
3393          if (!kernelLine) continue;          if (!kernelLine) continue;
3394    
3395          line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);   /* if title is supplied, the entry's title must match it. */
3396     if (title) {
3397        char *linetitle;
3398    
3399        line = getLineByType(LT_TITLE|LT_MENUENTRY, entry->lines);
3400        if (!line)
3401     continue;
3402    
3403        linetitle = extractTitle(cfg, line);
3404        if (!linetitle)
3405     continue;
3406        if (strcmp(title, linetitle)) {
3407     free(linetitle);
3408     continue;
3409        }
3410        free(linetitle);
3411     }
3412    
3413            line = getLineByType(LT_INITRD|LT_INITRD_EFI|LT_INITRD_16, entry->lines);
3414          if (line)          if (line)
3415              removeLine(entry, line);              removeLine(entry, line);
3416          if (prefix) {          if (prefix) {
# Line 3026  int updateInitrd(struct grubConfig * cfg Line 3421  int updateInitrd(struct grubConfig * cfg
3421   endLine = getLineByType(LT_ENTRY_END, entry->lines);   endLine = getLineByType(LT_ENTRY_END, entry->lines);
3422   if (endLine)   if (endLine)
3423      removeLine(entry, endLine);      removeLine(entry, endLine);
3424          line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),   enum lineType_e lt;
3425   kernelLine->indent, initrd);   switch(kernelLine->type) {
3426        case LT_KERNEL:
3427            lt = LT_INITRD;
3428     break;
3429        case LT_KERNEL_EFI:
3430            lt = LT_INITRD_EFI;
3431     break;
3432        case LT_KERNEL_16:
3433            lt = LT_INITRD_16;
3434     break;
3435        default:
3436            lt = preferredLineType(LT_INITRD, cfg->cfi);
3437     }
3438            line = addLine(entry, cfg->cfi, lt, kernelLine->indent, initrd);
3439          if (!line)          if (!line)
3440      return 1;      return 1;
3441   if (endLine) {   if (endLine) {
# Line 3386  int addNewKernel(struct grubConfig * con Line 3794  int addNewKernel(struct grubConfig * con
3794   const char * newKernelPath, const char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3795   const char * newKernelArgs, const char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3796   const char ** extraInitrds, int extraInitrdCount,   const char ** extraInitrds, int extraInitrdCount,
3797                   const char * newMBKernel, const char * newMBKernelArgs) {                   const char * newMBKernel, const char * newMBKernelArgs,
3798     const char * newDevTreePath) {
3799      struct singleEntry * new;      struct singleEntry * new;
3800      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3801      int needs;      int needs;
# Line 3427  int addNewKernel(struct grubConfig * con Line 3836  int addNewKernel(struct grubConfig * con
3836          needs |= NEED_MB;          needs |= NEED_MB;
3837          new->multiboot = 1;          new->multiboot = 1;
3838      }      }
3839        if (newDevTreePath && getKeywordByType(LT_DEVTREE, config->cfi))
3840     needs |= NEED_DEVTREE;
3841    
3842      if (template) {      if (template) {
3843   for (masterLine = template->lines;   for (masterLine = template->lines;
# Line 3612  int addNewKernel(struct grubConfig * con Line 4023  int addNewKernel(struct grubConfig * con
4023   newLine = addLineTmpl(new, tmplLine, newLine, NULL,   newLine = addLineTmpl(new, tmplLine, newLine, NULL,
4024   config->cfi);   config->cfi);
4025      }      }
4026        } else if (tmplLine->type == LT_DEVTREE &&
4027           tmplLine->numElements == 2 && newDevTreePath) {
4028            newLine = addLineTmpl(new, tmplLine, newLine,
4029          newDevTreePath + strlen(prefix),
4030          config->cfi);
4031     needs &= ~NEED_DEVTREE;
4032        } else if (tmplLine->type == LT_ENTRY_END && needs & NEED_DEVTREE) {
4033     const char *ndtp = newDevTreePath;
4034     if (!strncmp(newDevTreePath, prefix, strlen(prefix)))
4035        ndtp += strlen(prefix);
4036     newLine = addLine(new, config->cfi, LT_DEVTREE,
4037      config->secondaryIndent,
4038      ndtp);
4039     needs &= ~NEED_DEVTREE;
4040     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
4041      } else {      } else {
4042   /* pass through other lines from the template */   /* pass through other lines from the template */
4043   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);   newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
# Line 3625  int addNewKernel(struct grubConfig * con Line 4051  int addNewKernel(struct grubConfig * con
4051   switch (config->cfi->entryStart) {   switch (config->cfi->entryStart) {
4052      case LT_KERNEL:      case LT_KERNEL:
4053      case LT_KERNEL_EFI:      case LT_KERNEL_EFI:
4054        case LT_KERNEL_16:
4055   if (new->multiboot && config->cfi->mbHyperFirst) {   if (new->multiboot && config->cfi->mbHyperFirst) {
4056      /* fall through to LT_HYPER */      /* fall through to LT_HYPER */
4057   } else {   } else {
# Line 3686  int addNewKernel(struct grubConfig * con Line 4113  int addNewKernel(struct grubConfig * con
4113   }   }
4114      }      }
4115    
4116        struct singleLine *endLine = NULL;
4117        endLine = getLineByType(LT_ENTRY_END, new->lines);
4118        if (endLine) {
4119        removeLine(new, endLine);
4120        needs |= NEED_END;
4121        }
4122    
4123      /* add the remainder of the lines, i.e. those that either      /* add the remainder of the lines, i.e. those that either
4124       * weren't present in the template, or in the case of no template,       * weren't present in the template, or in the case of no template,
4125       * all the lines following the entryStart.       * all the lines following the entryStart.
# Line 3731  int addNewKernel(struct grubConfig * con Line 4165  int addNewKernel(struct grubConfig * con
4165   free(initrdVal);   free(initrdVal);
4166   needs &= ~NEED_INITRD;   needs &= ~NEED_INITRD;
4167      }      }
4168        if (needs & NEED_DEVTREE) {
4169     newLine = addLine(new, config->cfi, LT_DEVTREE,
4170      config->secondaryIndent,
4171      newDevTreePath);
4172     needs &= ~NEED_DEVTREE;
4173        }
4174    
4175        /* NEEDS_END must be last on bootloaders that need it... */
4176      if (needs & NEED_END) {      if (needs & NEED_END) {
4177   newLine = addLine(new, config->cfi, LT_ENTRY_END,   newLine = addLine(new, config->cfi, LT_ENTRY_END,
4178   config->secondaryIndent, NULL);   config->secondaryIndent, NULL);
# Line 3782  int main(int argc, const char ** argv) { Line 4224  int main(int argc, const char ** argv) {
4224      char * newKernelArgs = NULL;      char * newKernelArgs = NULL;
4225      char * newKernelInitrd = NULL;      char * newKernelInitrd = NULL;
4226      char * newKernelTitle = NULL;      char * newKernelTitle = NULL;
4227      char * newKernelVersion = NULL;      char * newDevTreePath = NULL;
4228      char * newMBKernel = NULL;      char * newMBKernel = NULL;
4229      char * newMBKernelArgs = NULL;      char * newMBKernelArgs = NULL;
4230      char * removeMBKernelArgs = NULL;      char * removeMBKernelArgs = NULL;
# Line 3792  int main(int argc, const char ** argv) { Line 4234  int main(int argc, const char ** argv) {
4234      char * removeArgs = NULL;      char * removeArgs = NULL;
4235      char * kernelInfo = NULL;      char * kernelInfo = NULL;
4236      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };      char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
4237        char * envPath = NULL;
4238      const char * chptr = NULL;      const char * chptr = NULL;
4239      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
4240      struct grubConfig * config;      struct grubConfig * config;
# Line 3839  int main(int argc, const char ** argv) { Line 4282  int main(int argc, const char ** argv) {
4282      _("display the index of the default kernel") },      _("display the index of the default kernel") },
4283   { "default-title", 0, 0, &displayDefaultTitle, 0,   { "default-title", 0, 0, &displayDefaultTitle, 0,
4284      _("display the title of the default kernel") },      _("display the title of the default kernel") },
4285     { "devtree", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4286        _("device tree file for new stanza"), _("dtb-path") },
4287     { "devtreedir", 0, POPT_ARG_STRING, &newDevTreePath, 0,
4288        _("device tree directory for new stanza"), _("dtb-path") },
4289   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
4290      _("configure elilo bootloader") },      _("configure elilo bootloader") },
4291   { "efi", 0, POPT_ARG_NONE, &isEfi, 0,   { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
4292      _("force grub2 stanzas to use efi") },      _("force grub2 stanzas to use efi") },
4293     { "env", 0, POPT_ARG_STRING, &envPath, 0,
4294        _("path for environment data"),
4295        _("path") },
4296   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,   { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
4297      _("configure extlinux bootloader (from syslinux)") },      _("configure extlinux bootloader (from syslinux)") },
4298   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
# Line 3899  int main(int argc, const char ** argv) { Line 4349  int main(int argc, const char ** argv) {
4349    
4350      signal(SIGSEGV, traceback);      signal(SIGSEGV, traceback);
4351    
4352        int i = 0;
4353        for (int j = 1; j < argc; j++)
4354     i += strlen(argv[j]) + 1;
4355        saved_command_line = malloc(i);
4356        if (!saved_command_line) {
4357     fprintf(stderr, "grubby: %m\n");
4358     exit(1);
4359        }
4360        saved_command_line[0] = '\0';
4361        for (int j = 1; j < argc; j++) {
4362     strcat(saved_command_line, argv[j]);
4363     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
4364        }
4365    
4366      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
4367      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
4368    
# Line 3942  int main(int argc, const char ** argv) { Line 4406  int main(int argc, const char ** argv) {
4406   return 1;   return 1;
4407      } else if (configureGrub2) {      } else if (configureGrub2) {
4408   cfi = &grub2ConfigType;   cfi = &grub2ConfigType;
4409     if (envPath)
4410        cfi->envFile = envPath;
4411      } else if (configureLilo) {      } else if (configureLilo) {
4412   cfi = &liloConfigType;   cfi = &liloConfigType;
4413      } else if (configureGrub) {      } else if (configureGrub) {
# Line 3985  int main(int argc, const char ** argv) { Line 4451  int main(int argc, const char ** argv) {
4451      grubConfig = cfi->defaultConfig;      grubConfig = cfi->defaultConfig;
4452      }      }
4453    
4454      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo ||
4455      newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4456      defaultKernel || displayDefaultIndex || displayDefaultTitle ||      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4457      (defaultIndex >= 0))) {      (defaultIndex >= 0))) {
# Line 3994  int main(int argc, const char ** argv) { Line 4460  int main(int argc, const char ** argv) {
4460   return 1;   return 1;
4461      }      }
4462    
4463      if ((displayDefault || kernelInfo) && (newKernelVersion || newKernelPath ||      if ((displayDefault || kernelInfo) && (newKernelPath ||
4464     removeKernelPath)) {     removeKernelPath)) {
4465   fprintf(stderr, _("grubby: --default-kernel and --info may not "   fprintf(stderr, _("grubby: --default-kernel and --info may not "
4466    "be used when adding or removing kernels\n"));    "be used when adding or removing kernels\n"));
# Line 4004  int main(int argc, const char ** argv) { Line 4470  int main(int argc, const char ** argv) {
4470      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4471   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4472   return 1;   return 1;
4473      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||      } else if (!newKernelPath && (copyDefault ||
4474    (newKernelInitrd && !updateKernelPath)||    (newKernelInitrd && !updateKernelPath)||
4475    makeDefault || extraInitrdCount > 0)) {    makeDefault || extraInitrdCount > 0)) {
4476   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
# Line 4142  int main(int argc, const char ** argv) { Line 4608  int main(int argc, const char ** argv) {
4608   return 0;   return 0;
4609      }      }
4610    
4611        if (grubConfig == NULL) {
4612     printf("Could not find bootloader configuration file.\n");
4613     exit(1);
4614        }
4615    
4616      config = readConfig(grubConfig, cfi);      config = readConfig(grubConfig, cfi);
4617      if (!config) return 1;      if (!config) return 1;
4618    
# Line 4151  int main(int argc, const char ** argv) { Line 4622  int main(int argc, const char ** argv) {
4622          char * rootspec;          char * rootspec;
4623    
4624   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4625     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4626     cfi->defaultIsSaved)
4627        config->defaultImage = 0;
4628   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4629   if (!entry) return 0;   if (!entry) return 0;
4630   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4631    
4632   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI|LT_KERNEL_16, entry->lines);
4633   if (!line) return 0;   if (!line) return 0;
4634    
4635          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 4169  int main(int argc, const char ** argv) { Line 4643  int main(int argc, const char ** argv) {
4643   struct singleEntry * entry;   struct singleEntry * entry;
4644    
4645   if (config->defaultImage == -1) return 0;   if (config->defaultImage == -1) return 0;
4646     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4647     cfi->defaultIsSaved)
4648        config->defaultImage = 0;
4649   entry = findEntryByIndex(config, config->defaultImage);   entry = findEntryByIndex(config, config->defaultImage);
4650   if (!entry) return 0;   if (!entry) return 0;
4651    
# Line 4191  int main(int argc, const char ** argv) { Line 4668  int main(int argc, const char ** argv) {
4668    
4669      } else if (displayDefaultIndex) {      } else if (displayDefaultIndex) {
4670          if (config->defaultImage == -1) return 0;          if (config->defaultImage == -1) return 0;
4671     if (config->defaultImage == DEFAULT_SAVED_GRUB2 &&
4672     cfi->defaultIsSaved)
4673        config->defaultImage = 0;
4674          printf("%i\n", config->defaultImage);          printf("%i\n", config->defaultImage);
4675            return 0;
4676    
4677      } else if (kernelInfo)      } else if (kernelInfo)
4678   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
# Line 4209  int main(int argc, const char ** argv) { Line 4690  int main(int argc, const char ** argv) {
4690      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4691                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4692      if (updateKernelPath && newKernelInitrd) {      if (updateKernelPath && newKernelInitrd) {
4693              if (updateInitrd(config, updateKernelPath, bootPrefix,      if (newMBKernel) {
4694                               newKernelInitrd)) return 1;      if (addMBInitrd(config, newMBKernel, updateKernelPath,
4695     bootPrefix, newKernelInitrd,
4696     newKernelTitle))
4697        return 1;
4698        } else {
4699        if (updateInitrd(config, updateKernelPath, bootPrefix,
4700     newKernelInitrd, newKernelTitle))
4701     return 1;
4702        }
4703      }      }
4704      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4705                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4706                       (const char **)extraInitrds, extraInitrdCount,                       (const char **)extraInitrds, extraInitrdCount,
4707                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs, newDevTreePath)) return 1;
4708            
4709    
4710      if (numEntries(config) == 0) {      if (numEntries(config) == 0) {

Legend:
Removed from v.2058  
changed lines
  Added in v.2980