Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1714 by niro, Sat Feb 18 00:32:14 2012 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39  #include "mount_by_label.h"  #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43    #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49  #define _(A) (A)  #define _(A) (A)
50    
51    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
52  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
53    
54  /* comments get lumped in with indention */  /* comments get lumped in with indention */
# Line 38  struct lineElement { Line 57  struct lineElement {
57      char * indent;      char * indent;
58  };  };
59    
60  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
61         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
62         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
63        LT_KERNEL       = 1 << 2,
64        LT_INITRD       = 1 << 3,
65        LT_HYPER        = 1 << 4,
66        LT_DEFAULT      = 1 << 5,
67        LT_MBMODULE     = 1 << 6,
68        LT_ROOT         = 1 << 7,
69        LT_FALLBACK     = 1 << 8,
70        LT_KERNELARGS   = 1 << 9,
71        LT_BOOT         = 1 << 10,
72        LT_BOOTROOT     = 1 << 11,
73        LT_LBA          = 1 << 12,
74        LT_OTHER        = 1 << 13,
75        LT_GENERIC      = 1 << 14,
76        LT_ECHO    = 1 << 16,
77        LT_MENUENTRY    = 1 << 17,
78        LT_ENTRY_END    = 1 << 18,
79        LT_SET_VARIABLE = 1 << 19,
80        LT_UNKNOWN      = 1 << 20,
81    };
82    
83  struct singleLine {  struct singleLine {
84      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 99  struct singleEntry {
99    
100  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */
101    
102  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
103  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
104  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
105  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
106  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
107    #define NEED_MB      (1 << 4)
108    #define NEED_END     (1 << 5)
109    
110  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
111  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
# Line 74  struct keywordTypes { Line 114  struct keywordTypes {
114      char * key;      char * key;
115      enum lineType_e type;      enum lineType_e type;
116      char nextChar;      char nextChar;
117  } ;      char separatorChar;
118    };
119    
120    struct configFileInfo;
121    
122    typedef const char *(*findConfigFunc)(struct configFileInfo *);
123    typedef const int (*writeLineFunc)(struct configFileInfo *,
124     struct singleLine *line);
125    
126  struct configFileInfo {  struct configFileInfo {
127      char * defaultConfig;      char * defaultConfig;
128        findConfigFunc findConfig;
129        writeLineFunc writeLine;
130      struct keywordTypes * keywords;      struct keywordTypes * keywords;
131      int defaultIsIndex;      int defaultIsIndex;
132        int defaultIsVariable;
133      int defaultSupportSaved;      int defaultSupportSaved;
134      enum lineType_e entrySeparator;      enum lineType_e entryStart;
135        enum lineType_e entryEnd;
136      int needsBootPrefix;      int needsBootPrefix;
137      int argsInQuotes;      int argsInQuotes;
138      int maxTitleLength;      int maxTitleLength;
139      int titleBracketed;      int titleBracketed;
140        int titlePosition;
141        int mbHyperFirst;
142        int mbInitRdIsModule;
143        int mbConcatArgs;
144        int mbAllowExtraInitRds;
145  };  };
146    
147  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 150  struct keywordTypes grubKeywords[] = {
150      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
151      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
152      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
153      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
154      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
155        { "kernel",     LT_HYPER,       ' ' },
156      { NULL,    0, 0 },      { NULL,    0, 0 },
157  };  };
158    
159  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
160      "/boot/grub/grub.conf",    /* defaultConfig */      .defaultConfig = "/boot/grub/grub.conf",
161      grubKeywords,    /* keywords */      .keywords = grubKeywords,
162      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
163      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
164      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
165      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
166      0,    /* argsInQuotes */      .mbHyperFirst = 1,
167      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
168      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
169    };
170    
171    struct keywordTypes grub2Keywords[] = {
172        { "menuentry",  LT_MENUENTRY,   ' ' },
173        { "}",          LT_ENTRY_END,   ' ' },
174        { "echo",       LT_ECHO,        ' ' },
175        { "set",        LT_SET_VARIABLE,' ', '=' },
176        { "root",       LT_BOOTROOT,    ' ' },
177        { "default",    LT_DEFAULT,     ' ' },
178        { "fallback",   LT_FALLBACK,    ' ' },
179        { "linux",      LT_KERNEL,      ' ' },
180        { "initrd",     LT_INITRD,      ' ', ' ' },
181        { "module",     LT_MBMODULE,    ' ' },
182        { "kernel",     LT_HYPER,       ' ' },
183        { NULL, 0, 0 },
184    };
185    
186    const char *grub2FindConfig(struct configFileInfo *cfi) {
187        static const char *configFiles[] = {
188     "/boot/grub/grub-efi.cfg",
189     "/boot/grub/grub.cfg",
190     NULL
191        };
192        static int i = -1;
193        static const char *grub_cfg = "/boot/grub/grub.cfg";
194    
195        if (i == -1) {
196     for (i = 0; configFiles[i] != NULL; i++) {
197        dbgPrintf("Checking \"%s\": ", configFiles[i]);
198        if (!access(configFiles[i], R_OK)) {
199     dbgPrintf("found\n");
200     return configFiles[i];
201        }
202     }
203        }
204    
205        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
206         * that isn't in grub1, and if it exists, return the config file path
207         * that they use. */
208        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
209     dbgPrintf("found\n");
210     return grub_cfg;
211        }
212    
213        dbgPrintf("not found\n");
214        return configFiles[i];
215    }
216    
217    struct configFileInfo grub2ConfigType = {
218        .findConfig = grub2FindConfig,
219        .keywords = grub2Keywords,
220        .defaultIsIndex = 1,
221        .defaultSupportSaved = 0,
222        .defaultIsVariable = 1,
223        .entryStart = LT_MENUENTRY,
224        .entryEnd = LT_ENTRY_END,
225        .titlePosition = 1,
226        .needsBootPrefix = 1,
227        .mbHyperFirst = 1,
228        .mbInitRdIsModule = 1,
229        .mbAllowExtraInitRds = 1,
230  };  };
231    
232  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 260  struct keywordTypes yabootKeywords[] = {
260      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
261      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
262      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
263      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
264      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
265      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
266      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 280  struct keywordTypes liloKeywords[] = {
280      { NULL,    0, 0 },      { NULL,    0, 0 },
281  };  };
282    
283    struct keywordTypes eliloKeywords[] = {
284        { "label",    LT_TITLE,    '=' },
285        { "root",    LT_ROOT,    '=' },
286        { "default",    LT_DEFAULT,    '=' },
287        { "image",    LT_KERNEL,    '=' },
288        { "initrd",    LT_INITRD,    '=' },
289        { "append",    LT_KERNELARGS,  '=' },
290        { "vmm",    LT_HYPER,       '=' },
291        { NULL,    0, 0 },
292    };
293    
294  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
295      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
296      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 312  struct keywordTypes ziplKeywords[] = {
312      { NULL,         0, 0 },      { NULL,         0, 0 },
313  };  };
314    
315    struct keywordTypes extlinuxKeywords[] = {
316        { "label",    LT_TITLE,    ' ' },
317        { "root",    LT_ROOT,    ' ' },
318        { "default",    LT_DEFAULT,    ' ' },
319        { "kernel",    LT_KERNEL,    ' ' },
320        { "initrd",    LT_INITRD,      ' ', ',' },
321        { "append",    LT_KERNELARGS,  ' ' },
322        { "prompt",     LT_UNKNOWN,     ' ' },
323        { NULL,    0, 0 },
324    };
325    int useextlinuxmenu;
326  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
327      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
328      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
329      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
330      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
331      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
332      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
333  };  };
334    
335  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
336      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
337      liloKeywords,    /* keywords */      .keywords = liloKeywords,
338      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
339      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
340      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
341  };  };
342    
343  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
344      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
345      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
346      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
347      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
348      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
349      1,    /* needsBootPrefix */      .maxTitleLength = 15,
350      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
351  };  };
352    
353  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
354      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
355      siloKeywords,    /* keywords */      .keywords = siloKeywords,
356      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
357      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
358      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
359      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
360  };  };
361    
362  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
363      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
364      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
365      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
366      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
367      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
368      0,    /* needsBootPrefix */  };
369      1,    /* argsInQuotes */  
370      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
371      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
372        .keywords = extlinuxKeywords,
373        .entryStart = LT_TITLE,
374        .needsBootPrefix = 1,
375        .maxTitleLength = 255,
376        .mbAllowExtraInitRds = 1,
377  };  };
378    
379  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 388  struct grubConfig {
388      struct configFileInfo * cfi;      struct configFileInfo * cfi;
389  };  };
390    
391    blkid_cache blkid;
392    
393  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
394  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
395       const char * path, const char * prefix,       const char * path, const char * prefix,
396       int * index);       int * index);
 static char * strndup(char * from, int len);  
397  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
398  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
399    struct singleLine * lineDup(struct singleLine * line);
400  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
401  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
402       struct configFileInfo * cfi);       struct configFileInfo * cfi);
403  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
404         struct configFileInfo * cfi);         struct configFileInfo * cfi);
405  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
406    static void requote(struct singleLine *line, struct configFileInfo * cfi);
407  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
408      char * to;    const char * item, int insertHere,
409      struct configFileInfo * cfi);
410      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
411      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
412      to[len] = '\0';        struct configFileInfo * cfi);
413    static enum lineType_e getTypeByKeyword(char * keyword,
414      return to;   struct configFileInfo * cfi);
415  }  static struct singleLine * getLineByType(enum lineType_e type,
416     struct singleLine * line);
417    static int checkForExtLinux(struct grubConfig * config);
418    struct singleLine * addLineTmpl(struct singleEntry * entry,
419                                    struct singleLine * tmplLine,
420                                    struct singleLine * prevLine,
421                                    const char * val,
422     struct configFileInfo * cfi);
423    struct singleLine *  addLine(struct singleEntry * entry,
424                                 struct configFileInfo * cfi,
425                                 enum lineType_e type, char * defaultIndent,
426                                 const char * val);
427    
428  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
429  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 458  static char * sdupprintf(const char *for
458      return buf;      return buf;
459  }  }
460    
461    static struct keywordTypes * getKeywordByType(enum lineType_e type,
462          struct configFileInfo * cfi) {
463        struct keywordTypes * kw;
464        for (kw = cfi->keywords; kw->key; kw++) {
465     if (kw->type == type)
466        return kw;
467        }
468        return NULL;
469    }
470    
471    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
472        struct keywordTypes *kt = getKeywordByType(type, cfi);
473        if (kt)
474     return kt->key;
475        return "unknown";
476    }
477    
478    static char * getpathbyspec(char *device) {
479        if (!blkid)
480            blkid_get_cache(&blkid, NULL);
481    
482        return blkid_get_devname(blkid, device, NULL);
483    }
484    
485    static char * getuuidbydev(char *device) {
486        if (!blkid)
487     blkid_get_cache(&blkid, NULL);
488    
489        return blkid_get_tag_value(blkid, "UUID", device);
490    }
491    
492    static enum lineType_e getTypeByKeyword(char * keyword,
493     struct configFileInfo * cfi) {
494        struct keywordTypes * kw;
495        for (kw = cfi->keywords; kw->key; kw++) {
496     if (!strcmp(keyword, kw->key))
497        return kw->type;
498        }
499        return LT_UNKNOWN;
500    }
501    
502    static struct singleLine * getLineByType(enum lineType_e type,
503     struct singleLine * line) {
504        dbgPrintf("getLineByType(%d): ", type);
505        for (; line; line = line->next) {
506     dbgPrintf("%d:%s ", line->type,
507      line->numElements ? line->elements[0].item : "(empty)");
508     if (line->type & type) break;
509        }
510        dbgPrintf(line ? "\n" : " (failed)\n");
511        return line;
512    }
513    
514  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
515      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
516          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
517          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
518              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 524  static int isBracketedTitle(struct singl
524      return 0;      return 0;
525  }  }
526    
527  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
528                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
529      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
530   return 0;   (cfi->titleBracketed && isBracketedTitle(line));
     if (line->type == cfi->entrySeparator)  
         return 1;  
     if (line->type == LT_OTHER)  
         return 1;  
     if (cfi->titleBracketed && isBracketedTitle(line)) {  
         return 1;  
     }  
     return 0;  
531  }  }
532    
533  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 578  static void lineInit(struct singleLine *
578      line->next = NULL;      line->next = NULL;
579  }  }
580    
581    struct singleLine * lineDup(struct singleLine * line) {
582        int i;
583        struct singleLine * newLine = malloc(sizeof(*newLine));
584    
585        newLine->indent = strdup(line->indent);
586        newLine->next = NULL;
587        newLine->type = line->type;
588        newLine->numElements = line->numElements;
589        newLine->elements = malloc(sizeof(*newLine->elements) *
590           newLine->numElements);
591    
592        for (i = 0; i < newLine->numElements; i++) {
593     newLine->elements[i].indent = strdup(line->elements[i].indent);
594     newLine->elements[i].item = strdup(line->elements[i].item);
595        }
596    
597        return newLine;
598    }
599    
600  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
601      int i;      int i;
602    
# Line 414  static int lineWrite(FILE * out, struct Line 622  static int lineWrite(FILE * out, struct
622      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
623    
624   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
625   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
626        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
627      }      }
628    
629      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 642  static int getNextLine(char ** bufPtr, s
642      char * chptr;      char * chptr;
643      int elementsAlloced = 0;      int elementsAlloced = 0;
644      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
645      int first = 1;      int first = 1;
     int i;  
646    
647      lineFree(line);      lineFree(line);
648    
# Line 489  static int getNextLine(char ** bufPtr, s Line 696  static int getNextLine(char ** bufPtr, s
696      if (!line->numElements)      if (!line->numElements)
697   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
698      else {      else {
699   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
700      if (!strcmp(line->elements[0].item, keywords[i].key)) break;   if (line->type == LT_UNKNOWN) {
   
  if (keywords[i].key) {  
     line->type = keywords[i].type;  
  } else {  
     line->type = LT_UNKNOWN;  
               
701              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
702               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
703              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 733  static int getNextLine(char ** bufPtr, s
733   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
734   line->numElements = 0;   line->numElements = 0;
735      }      }
736     } else {
737     struct keywordTypes *kw;
738    
739     kw = getKeywordByType(line->type, cfi);
740    
741     /* space isn't the only separator, we need to split
742     * elements up more
743     */
744     if (!isspace(kw->separatorChar)) {
745        int i;
746        char indent[2] = "";
747        indent[0] = kw->separatorChar;
748        for (i = 1; i < line->numElements; i++) {
749     char *p;
750     int j;
751     int numNewElements;
752    
753     numNewElements = 0;
754     p = line->elements[i].item;
755     while (*p != '\0') {
756     if (*p == kw->separatorChar)
757     numNewElements++;
758     p++;
759     }
760     if (line->numElements + numNewElements >= elementsAlloced) {
761     elementsAlloced += numNewElements + 5;
762     line->elements = realloc(line->elements,
763        sizeof(*line->elements) * elementsAlloced);
764     }
765    
766     for (j = line->numElements; j > i; j--) {
767     line->elements[j + numNewElements] = line->elements[j];
768     }
769     line->numElements += numNewElements;
770    
771     p = line->elements[i].item;
772     while (*p != '\0') {
773    
774     while (*p != kw->separatorChar && *p != '\0') p++;
775     if (*p == '\0') {
776     break;
777     }
778    
779     free(line->elements[i].indent);
780     line->elements[i].indent = strdup(indent);
781     *p++ = '\0';
782     i++;
783     line->elements[i].item = strdup(p);
784     line->elements[i].indent = strdup("");
785     p = line->elements[i].item;
786     }
787        }
788     }
789   }   }
790      }      }
791    
# Line 595  static struct grubConfig * readConfig(co Line 849  static struct grubConfig * readConfig(co
849      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
850   }   }
851    
852   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi)) {
853      sawEntry = 1;      sawEntry = 1;
854      if (!entry) {      if (!entry) {
855   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 865  static struct grubConfig * readConfig(co
865      entry->next = NULL;      entry->next = NULL;
866   }   }
867    
868   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
869        int i;
870        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
871        dbgPrintf("%s", line->indent);
872        for (i = 0; i < line->numElements; i++)
873     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
874        dbgPrintf("\n");
875        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
876        if (kwType && line->numElements == 3 &&
877        !strcmp(line->elements[1].item, kwType->key)) {
878     dbgPrintf("Line sets default config\n");
879     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
880     defaultLine = line;
881        }
882     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
883      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
884      defaultLine = line;      defaultLine = line;
885    
886            } else if (line->type == LT_KERNEL) {
887        /* if by some freak chance this is multiboot and the "module"
888         * lines came earlier in the template, make sure to use LT_HYPER
889         * instead of LT_KERNEL now
890         */
891        if (entry->multiboot)
892     line->type = LT_HYPER;
893    
894          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
895        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
896         * instead, now that we know this is a multiboot entry.
897         * This only applies to grub, but that's the only place we
898         * should find LT_MBMODULE lines anyway.
899         */
900        struct singleLine * l;
901        for (l = entry->lines; l; l = l->next) {
902     if (l->type == LT_HYPER)
903        break;
904     else if (l->type == LT_KERNEL) {
905        l->type = LT_HYPER;
906        break;
907     }
908        }
909              entry->multiboot = 1;              entry->multiboot = 1;
910    
911     } else if (line->type == LT_HYPER) {
912        entry->multiboot = 1;
913    
914   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
915      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
916      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
917    
918   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
919      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
920      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 939  static struct grubConfig * readConfig(co
939      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
940      line->elements[1].item = buf;      line->elements[1].item = buf;
941      line->numElements = 2;      line->numElements = 2;
942    
943   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
944      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
945         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 652  static struct grubConfig * readConfig(co Line 949  static struct grubConfig * readConfig(co
949   int last, len;   int last, len;
950    
951   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
952      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
953     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
954    
955   last = line->numElements - 1;   last = line->numElements - 1;
956   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
957   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
958      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
959      }      }
   
960   }   }
961    
962   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
# Line 680  static struct grubConfig * readConfig(co Line 976  static struct grubConfig * readConfig(co
976   movedLine = 1;   movedLine = 1;
977   continue; /* without setting 'last' */   continue; /* without setting 'last' */
978   }   }
979    
980   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
981     which was moved, drop it. */     which was moved, drop it. */
982   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {
# Line 695  static struct grubConfig * readConfig(co Line 992  static struct grubConfig * readConfig(co
992   entry->lines = line;   entry->lines = line;
993      else      else
994   last->next = line;   last->next = line;
995        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
996    
997        /* we could have seen this outside of an entry... if so, we
998         * ignore it like any other line we don't grok */
999        if (line->type == LT_ENTRY_END && sawEntry)
1000     sawEntry = 0;
1001   } else {   } else {
1002      if (!cfg->theLines)      if (!cfg->theLines)
1003   cfg->theLines = line;   cfg->theLines = line;
1004      else {      else
1005   last->next = line;   last->next = line;
1006      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1007   }   }
1008    
1009   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1011  static struct grubConfig * readConfig(co
1011    
1012      free(incoming);      free(incoming);
1013    
1014        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1015      if (defaultLine) {      if (defaultLine) {
1016   if (cfi->defaultSupportSaved &&   if (cfi->defaultIsVariable) {
1017        char *value = defaultLine->elements[2].item;
1018        while (*value && (*value == '"' || *value == '\'' ||
1019        *value == ' ' || *value == '\t'))
1020     value++;
1021        cfg->defaultImage = strtol(value, &end, 10);
1022        while (*end && (*end == '"' || *end == '\'' ||
1023        *end == ' ' || *end == '\t'))
1024     end++;
1025        if (*end) cfg->defaultImage = -1;
1026     } else if (cfi->defaultSupportSaved &&
1027   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1028      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1029   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1044  static struct grubConfig * readConfig(co
1044                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1045                  }                  }
1046   i++;   i++;
1047     entry = NULL;
1048      }      }
1049    
1050      if (entry) cfg->defaultImage = i;      if (entry){
1051            cfg->defaultImage = i;
1052        }else{
1053            cfg->defaultImage = -1;
1054        }
1055   }   }
1056        } else {
1057            cfg->defaultImage = 0;
1058      }      }
1059    
1060      return cfg;      return cfg;
# Line 751  static void writeDefault(FILE * out, cha Line 1072  static void writeDefault(FILE * out, cha
1072   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1073      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1074   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1075      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1076      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1077     cfg->defaultImage);
1078        } else {
1079     fprintf(out, "%sdefault%s%d\n", indent, separator,
1080     cfg->defaultImage);
1081        }
1082   } else {   } else {
1083      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1084    
# Line 769  static void writeDefault(FILE * out, cha Line 1095  static void writeDefault(FILE * out, cha
1095    
1096      if (!entry) return;      if (!entry) return;
1097    
1098      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1099    
1100      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1101   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1129  static int writeConfig(struct grubConfig
1129      int rc;      int rc;
1130    
1131      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1132         directory to / */         directory to the dir of the symlink */
1133      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1134      do {      do {
1135   buf = alloca(len + 1);   buf = alloca(len + 1);
1136   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1137   if (rc == len) len += 256;   if (rc == len) len += 256;
1138      } while (rc == len);      } while (rc == len);
1139            
# Line 843  static int writeConfig(struct grubConfig Line 1168  static int writeConfig(struct grubConfig
1168      }      }
1169    
1170      line = cfg->theLines;      line = cfg->theLines;
1171        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1172      while (line) {      while (line) {
1173   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1174     line->numElements == 3 &&
1175     !strcmp(line->elements[1].item, defaultKw->key)) {
1176        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1177        needs &= ~MAIN_DEFAULT;
1178     } else if (line->type == LT_DEFAULT) {
1179      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1180      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1181   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1243  static int numEntries(struct grubConfig
1243      return i;      return i;
1244  }  }
1245    
1246    static char *findDiskForRoot()
1247    {
1248        int fd;
1249        char buf[65536];
1250        char *devname;
1251        char *chptr;
1252        int rc;
1253    
1254        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1255            fprintf(stderr, "grubby: failed to open %s: %s\n",
1256                    _PATH_MOUNTED, strerror(errno));
1257            return NULL;
1258        }
1259    
1260        rc = read(fd, buf, sizeof(buf) - 1);
1261        if (rc <= 0) {
1262            fprintf(stderr, "grubby: failed to read %s: %s\n",
1263                    _PATH_MOUNTED, strerror(errno));
1264            close(fd);
1265            return NULL;
1266        }
1267        close(fd);
1268        buf[rc] = '\0';
1269        chptr = buf;
1270    
1271        while (chptr && chptr != buf+rc) {
1272            devname = chptr;
1273    
1274            /*
1275             * The first column of a mtab entry is the device, but if the entry is a
1276             * special device it won't start with /, so move on to the next line.
1277             */
1278            if (*devname != '/') {
1279                chptr = strchr(chptr, '\n');
1280                if (chptr)
1281                    chptr++;
1282                continue;
1283            }
1284    
1285            /* Seek to the next space */
1286            chptr = strchr(chptr, ' ');
1287            if (!chptr) {
1288                fprintf(stderr, "grubby: error parsing %s: %s\n",
1289                        _PATH_MOUNTED, strerror(errno));
1290                return NULL;
1291            }
1292    
1293            /*
1294             * The second column of a mtab entry is the mount point, we are looking
1295             * for '/' obviously.
1296             */
1297            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1298                /*
1299                 * Move back 2, which is the first space after the device name, set
1300                 * it to \0 so strdup will just get the devicename.
1301                 */
1302                chptr -= 2;
1303                *chptr = '\0';
1304                return strdup(devname);
1305            }
1306    
1307            /* Next line */
1308            chptr = strchr(chptr, '\n');
1309            if (chptr)
1310                chptr++;
1311        }
1312    
1313        return NULL;
1314    }
1315    
1316  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1317    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1318      struct singleLine * line;      struct singleLine * line;
1319      char * fullName;      char * fullName;
1320      int i;      int i;
     struct stat sb, sb2;  
1321      char * dev;      char * dev;
     char * end;  
1322      char * rootspec;      char * rootspec;
1323        char * rootdev;
1324    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
       
     if (!line) return 0;  
1325      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) return 0;
1326      if (line->numElements < 2) return 0;  
1327        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1328        if (!line || line->numElements < 2) return 0;
1329    
1330      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1331    
# Line 935  int suitableImage(struct singleEntry * e Line 1333  int suitableImage(struct singleEntry * e
1333        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1334      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1335      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1336              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
                                       strlen(rootspec) : 0));  
1337      if (access(fullName, R_OK)) return 0;      if (access(fullName, R_OK)) return 0;
1338    
1339      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 945  int suitableImage(struct singleEntry * e Line 1342  int suitableImage(struct singleEntry * e
1342   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1343      } else {      } else {
1344   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1345   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1346    
1347   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1348      dev = line->elements[1].item;      dev = line->elements[1].item;
1349   } else {   } else {
1350              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1351      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */       * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1352      line = entry->lines;       */
1353        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1354    
1355              /* failed to find one */              /* failed to find one */
1356              if (!line) return 0;              if (!line) return 0;
# Line 973  int suitableImage(struct singleEntry * e Line 1366  int suitableImage(struct singleEntry * e
1366   }   }
1367      }      }
1368    
1369      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1370   dev += 6;      if (!dev)
1371            return 0;
1372   /* check which device has this label */  
1373   dev = get_spec_by_volume_label(dev, &i, &i);      rootdev = findDiskForRoot();
1374   if (!dev) return 0;      if (!rootdev)
1375     return 0;
1376    
1377        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1378            free(rootdev);
1379            return 0;
1380      }      }
1381    
1382      if (*dev == '/') {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1383   if (stat(dev, &sb))   free(rootdev);
1384      return 0;          return 0;
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1385      }      }
     stat("/", &sb2);  
1386    
1387      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1388    
1389      return 1;      return 1;
1390  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1428  struct singleEntry * findEntryByPath(str
1428   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1429   if (!entry) return NULL;   if (!entry) return NULL;
1430    
1431   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1432   if (!line) return NULL;   if (!line) return NULL;
1433    
1434   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1470  struct singleEntry * findEntryByPath(str
1470      kernel += 6;      kernel += 6;
1471   }   }
1472    
1473   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1474      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1475    
1476        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1477    
1478      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1479                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1480          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1481                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1482                              kernel + strlen(prefix)))       checkType, line);
1483                      break;   if (!line) break;  /* not found in this entry */
1484              }  
1485                 if (line && line->numElements >= 2) {
1486              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1487              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1488                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1489                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1490                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1491                      if (!strcmp(line->elements[1].item  +   }
1492                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1493    
1494      i++;      /* make sure this entry has a kernel identifier; this skips
1495         * non-Linux boot entries (could find netbsd etc, though, which is
1496         * unfortunate)
1497         */
1498        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1499     break; /* found 'im! */
1500   }   }
1501    
1502   if (index) *index = i;   if (index) *index = i;
1503      }      }
1504    
     if (!entry) return NULL;  
   
     /* make sure this entry has a kernel identifier; this skips non-Linux  
        boot entries (could find netbsd etc, though, which is unfortunate) */  
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
     if (!line) {  
  if (!index) index = &i;  
  (*index)++;  
  return findEntryByPath(config, kernel, prefix, index);  
     }  
   
1505      return entry;      return entry;
1506  }  }
1507    
# Line 1286  void displayEntry(struct singleEntry * e Line 1666  void displayEntry(struct singleEntry * e
1666      char * root = NULL;      char * root = NULL;
1667      int i;      int i;
1668    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1669      printf("index=%d\n", index);      printf("index=%d\n", index);
1670    
1671        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1672        if (!line) {
1673            printf("non linux entry\n");
1674            return;
1675        }
1676    
1677      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1678    
1679      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1691  void displayEntry(struct singleEntry * e
1691   }   }
1692   printf("\"\n");   printf("\"\n");
1693      } else {      } else {
1694   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1695   if (line) {   if (line) {
1696      char * s;      char * s;
1697    
# Line 1334  void displayEntry(struct singleEntry * e Line 1715  void displayEntry(struct singleEntry * e
1715      }      }
1716    
1717      if (!root) {      if (!root) {
1718   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1719   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1720      root=line->elements[1].item;      root=line->elements[1].item;
1721      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1730  void displayEntry(struct singleEntry * e
1730   printf("root=%s\n", s);   printf("root=%s\n", s);
1731      }      }
1732    
1733      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1734    
1735      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1736   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1747  int parseSysconfigGrub(int * lbaPtr, cha
1747      char * start;      char * start;
1748      char * param;      char * param;
1749    
1750      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1751      if (!in) return 1;      if (!in) return 1;
1752    
1753      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1809  int displayInfo(struct grubConfig * conf
1809   return 1;   return 1;
1810      }      }
1811    
1812      /* this is a horrible hack to support /etc/sysconfig/grub; there must      /* this is a horrible hack to support /etc/conf.d/grub; there must
1813         be a better way */         be a better way */
1814      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1815   dumpSysconfigGrub();   dumpSysconfigGrub();
1816      } else {      } else {
1817   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1818   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1819      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1820   }   }
1821    
1822   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1823   if (line) printf("lba\n");   if (line) printf("lba\n");
1824      }      }
1825    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1834  int displayInfo(struct grubConfig * conf
1834      return 0;      return 0;
1835  }  }
1836    
1837    struct singleLine * addLineTmpl(struct singleEntry * entry,
1838     struct singleLine * tmplLine,
1839     struct singleLine * prevLine,
1840     const char * val,
1841     struct configFileInfo * cfi)
1842    {
1843        struct singleLine * newLine = lineDup(tmplLine);
1844    
1845        if (val) {
1846     /* override the inherited value with our own.
1847     * This is a little weak because it only applies to elements[1]
1848     */
1849     if (newLine->numElements > 1)
1850        removeElement(newLine, 1);
1851     insertElement(newLine, val, 1, cfi);
1852    
1853     /* but try to keep the rootspec from the template... sigh */
1854     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1855        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1856        if (rootspec != NULL) {
1857     free(newLine->elements[1].item);
1858     newLine->elements[1].item =
1859        sdupprintf("%s%s", rootspec, val);
1860        }
1861     }
1862        }
1863    
1864        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1865          newLine->elements[0].item : "");
1866    
1867        if (!entry->lines) {
1868     /* first one on the list */
1869     entry->lines = newLine;
1870        } else if (prevLine) {
1871     /* add after prevLine */
1872     newLine->next = prevLine->next;
1873     prevLine->next = newLine;
1874        }
1875    
1876        return newLine;
1877    }
1878    
1879  /* val may be NULL */  /* val may be NULL */
1880  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1881       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1882       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1883       char * val) {       const char * val) {
1884      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1885      int i;      struct keywordTypes * kw;
1886        struct singleLine tmpl;
1887    
1888      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1889   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1890      if (type != LT_TITLE || !cfi->titleBracketed)       */
1891          if (!cfi->keywords[i].key) abort();  
1892        if (type == LT_TITLE && cfi->titleBracketed) {
1893     /* we're doing a bracketed title (zipl) */
1894     tmpl.type = type;
1895     tmpl.numElements = 1;
1896     tmpl.elements = alloca(sizeof(*tmpl.elements));
1897     tmpl.elements[0].item = alloca(strlen(val)+3);
1898     sprintf(tmpl.elements[0].item, "[%s]", val);
1899     tmpl.elements[0].indent = "";
1900     val = NULL;
1901        } else if (type == LT_MENUENTRY) {
1902     char *lineend = "--class gnu-linux --class gnu --class os {";
1903     if (!val) {
1904        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
1905        abort();
1906     }
1907     kw = getKeywordByType(type, cfi);
1908     if (!kw) {
1909        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1910        abort();
1911     }
1912     tmpl.indent = "";
1913     tmpl.type = type;
1914     tmpl.numElements = 3;
1915     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1916     tmpl.elements[0].item = kw->key;
1917     tmpl.elements[0].indent = alloca(2);
1918     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1919     tmpl.elements[1].item = (char *)val;
1920     tmpl.elements[1].indent = alloca(2);
1921     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
1922     tmpl.elements[2].item = alloca(strlen(lineend)+1);
1923     strcpy(tmpl.elements[2].item, lineend);
1924     tmpl.elements[2].indent = "";
1925        } else {
1926     kw = getKeywordByType(type, cfi);
1927     if (!kw) {
1928        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1929        abort();
1930     }
1931     tmpl.type = type;
1932     tmpl.numElements = val ? 2 : 1;
1933     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1934     tmpl.elements[0].item = kw->key;
1935     tmpl.elements[0].indent = alloca(2);
1936     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1937     if (val) {
1938        tmpl.elements[1].item = (char *)val;
1939        tmpl.elements[1].indent = "";
1940     }
1941        }
1942    
1943      /* The last non-empty line gives us the indention to us and the line      /* The last non-empty line gives us the indention to us and the line
1944         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1945         may not be ideal? If there are no lines or we are looking at the         may not be ideal? If there are no lines or we are looking at the
1946         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1947         differently from the rest) */         differently from the rest) */
1948      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1949   line = entry->lines;   if (line->numElements) prev = line;
1950   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1951   while (line) {   if (!line->next && !prev) prev = line;
     if (line->numElements) prev = line;  
     line = line->next;  
  }  
  if (!prev) {  
     /* just use the last line */  
     prev = entry->lines;  
     while (prev->next) prev = prev->next;  
  }  
   
  line = prev->next;  
  prev->next = malloc(sizeof(*line));  
  prev->next->next = line;  
  line = prev->next;  
   
  if (prev == entry->lines)  
     line->indent = strdup(defaultIndent);  
  else  
     line->indent = strdup(prev->indent);  
     } else {  
  line = malloc(sizeof(*line));  
  line->indent = strdup(defaultIndent);  
  line->next = NULL;  
1952      }      }
1953    
1954      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
1955          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
1956          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
1957          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
1958          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
1959          line->elements[0].indent = malloc(2);   else
1960          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
1961          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
1962             if (menuEntry)
1963          if (val) {      tmpl.indent = "\t";
1964              line->elements[1].item = val;   else if (prev == entry->lines)
1965              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
1966          }   else
1967      } else {      tmpl.indent = prev->indent;
         /* we're doing the title of a bracketed title (zipl) */  
         line->type = type;  
         line->numElements = 1;  
         line->elements = malloc(sizeof(*line->elements) * line->numElements);  
   
         line->elements[0].item = malloc(strlen(val) + 3);  
         sprintf(line->elements[0].item, "[%s]", val);  
         line->elements[0].indent = strdup("");  
1968      }      }
1969    
1970      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1971  }  }
1972    
1973  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 1992  void removeLine(struct singleEntry * ent
1992      free(line);      free(line);
1993  }  }
1994    
1995    static int isquote(char q)
1996    {
1997        if (q == '\'' || q == '\"')
1998     return 1;
1999        return 0;
2000    }
2001    
2002    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2003    {
2004        struct singleLine newLine = {
2005     .indent = tmplLine->indent,
2006     .type = tmplLine->type,
2007     .next = tmplLine->next,
2008        };
2009        int firstQuotedItem = -1;
2010        int quoteLen = 0;
2011        int j;
2012        int element = 0;
2013        char *c;
2014    
2015        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2016        strcpy(c, tmplLine->elements[0].item);
2017        insertElement(&newLine, c, element++, cfi);
2018        free(c);
2019        c = NULL;
2020    
2021        for (j = 1; j < tmplLine->numElements; j++) {
2022     if (firstQuotedItem == -1) {
2023        quoteLen += strlen(tmplLine->elements[j].item);
2024        
2025        if (isquote(tmplLine->elements[j].item[0])) {
2026     firstQuotedItem = j;
2027            quoteLen += strlen(tmplLine->elements[j].indent);
2028        } else {
2029     c = malloc(quoteLen + 1);
2030     strcpy(c, tmplLine->elements[j].item);
2031     insertElement(&newLine, c, element++, cfi);
2032     free(c);
2033     quoteLen = 0;
2034        }
2035     } else {
2036        int itemlen = strlen(tmplLine->elements[j].item);
2037        quoteLen += itemlen;
2038        quoteLen += strlen(tmplLine->elements[j].indent);
2039        
2040        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2041     c = malloc(quoteLen + 1);
2042     c[0] = '\0';
2043     for (int i = firstQuotedItem; i < j+1; i++) {
2044        strcat(c, tmplLine->elements[i].item);
2045        strcat(c, tmplLine->elements[i].indent);
2046     }
2047     insertElement(&newLine, c, element++, cfi);
2048     free(c);
2049    
2050     firstQuotedItem = -1;
2051     quoteLen = 0;
2052        }
2053     }
2054        }
2055        while (tmplLine->numElements)
2056     removeElement(tmplLine, 0);
2057        if (tmplLine->elements)
2058     free(tmplLine->elements);
2059    
2060        tmplLine->numElements = newLine.numElements;
2061        tmplLine->elements = newLine.elements;
2062    }
2063    
2064    static void insertElement(struct singleLine * line,
2065      const char * item, int insertHere,
2066      struct configFileInfo * cfi)
2067    {
2068        struct keywordTypes * kw;
2069        char indent[2] = "";
2070    
2071        /* sanity check */
2072        if (insertHere > line->numElements) {
2073     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2074      insertHere, line->numElements);
2075     insertHere = line->numElements;
2076        }
2077    
2078        line->elements = realloc(line->elements, (line->numElements + 1) *
2079         sizeof(*line->elements));
2080        memmove(&line->elements[insertHere+1],
2081        &line->elements[insertHere],
2082        (line->numElements - insertHere) *
2083        sizeof(*line->elements));
2084        line->elements[insertHere].item = strdup(item);
2085    
2086        kw = getKeywordByType(line->type, cfi);
2087    
2088        if (line->numElements == 0) {
2089     indent[0] = '\0';
2090        } else if (insertHere == 0) {
2091     indent[0] = kw->nextChar;
2092        } else if (kw->separatorChar != '\0') {
2093     indent[0] = kw->separatorChar;
2094        } else {
2095     indent[0] = ' ';
2096        }
2097    
2098        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2099     /* move the end-of-line forward */
2100     line->elements[insertHere].indent =
2101        line->elements[insertHere-1].indent;
2102     line->elements[insertHere-1].indent = strdup(indent);
2103        } else {
2104     line->elements[insertHere].indent = strdup(indent);
2105        }
2106    
2107        line->numElements++;
2108    
2109        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2110          line->elements[0].item,
2111          line->elements[insertHere].item,
2112          line->elements[insertHere].indent,
2113          insertHere);
2114    }
2115    
2116    static void removeElement(struct singleLine * line, int removeHere) {
2117        int i;
2118    
2119        /* sanity check */
2120        if (removeHere >= line->numElements) return;
2121    
2122        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2123          removeHere, line->elements[removeHere].item);
2124    
2125        free(line->elements[removeHere].item);
2126    
2127        if (removeHere > 1) {
2128     /* previous argument gets this argument's post-indentation */
2129     free(line->elements[removeHere-1].indent);
2130     line->elements[removeHere-1].indent =
2131        line->elements[removeHere].indent;
2132        } else {
2133     free(line->elements[removeHere].indent);
2134        }
2135    
2136        /* now collapse the array, but don't bother to realloc smaller */
2137        for (i = removeHere; i < line->numElements - 1; i++)
2138     line->elements[i] = line->elements[i + 1];
2139    
2140        line->numElements--;
2141    }
2142    
2143  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2144      char * first, * second;      char * first, * second;
2145      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2162  int updateActualImage(struct grubConfig
2162      struct singleEntry * entry;      struct singleEntry * entry;
2163      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2164      int index = 0;      int index = 0;
2165      int i, j, k;      int i, k;
2166      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2167      const char ** arg;      const char ** arg;
2168      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2169      int firstElement;      int firstElement;
2170      int *usedElements, *usedArgs;      int *usedElements;
2171        int doreplace;
2172    
2173      if (!image) return 0;      if (!image) return 0;
2174    
# Line 1609  int updateActualImage(struct grubConfig Line 2195  int updateActualImage(struct grubConfig
2195   }   }
2196      }      }
2197    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2198    
2199      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2200   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2201    
2202      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2203   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2204    
2205      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2206    
2207      k = 0;   if (multibootArgs && !entry->multiboot)
2208      for (arg = newArgs; *arg; arg++)      continue;
2209          k++;  
2210      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2211     * LT_KERNELARGS, use that.  Otherwise use
2212     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2213     */
2214     if (useKernelArgs) {
2215        line = getLineByType(LT_KERNELARGS, entry->lines);
2216        if (!line) {
2217     /* no LT_KERNELARGS, need to add it */
2218     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2219           cfg->secondaryIndent, NULL);
2220        }
2221        firstElement = 1;
2222    
2223      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2224   index++;      line = getLineByType(LT_HYPER, entry->lines);
2225        if (!line) {
2226     /* a multiboot entry without LT_HYPER? */
2227     continue;
2228        }
2229        firstElement = 2;
2230    
2231   line = entry->lines;   } else {
2232   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2233   if (!line) continue;      if (!line) {
2234   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2235     continue;
2236          if (entry->multiboot && !multibootArgs) {      }
2237              /* first mb module line is the real kernel */      firstElement = 2;
             while (line && line->type != LT_MBMODULE) line = line->next;  
             firstElement = 2;  
         } else if (useKernelArgs) {  
     while (line && line->type != LT_KERNELARGS) line = line->next;  
     firstElement = 1;  
2238   }   }
2239    
2240   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2241      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2242      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2243     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2244        /* this is a multiboot entry, make sure there's
2245         * -- on the args line
2246         */
2247        for (i = firstElement; i < line->numElements; i++) {
2248     if (!strcmp(line->elements[i].item, "--"))
2249        break;
2250        }
2251        if (i == line->numElements) {
2252     /* assume all existing args are kernel args,
2253     * prepend -- to make it official
2254     */
2255     insertElement(line, "--", firstElement, cfg->cfi);
2256     i = firstElement;
2257        }
2258        if (!multibootArgs) {
2259     /* kernel args start after the -- */
2260     firstElement = i + 1;
2261        }
2262     } else if (cfg->cfi->mbConcatArgs) {
2263        /* this is a non-multiboot entry, remove hyper args */
2264        for (i = firstElement; i < line->numElements; i++) {
2265     if (!strcmp(line->elements[i].item, "--"))
2266        break;
2267        }
2268        if (i < line->numElements) {
2269     /* remove args up to -- */
2270     while (strcmp(line->elements[firstElement].item, "--"))
2271        removeElement(line, firstElement);
2272     /* remove -- */
2273     removeElement(line, firstElement);
2274        }
2275   }   }
2276    
2277          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2278    
2279          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2280   for (arg = newArgs; *arg; arg++) {  
2281              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2282      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2283     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2284        !strcmp(line->elements[i].item, "--"))
2285     {
2286        /* reached the end of hyper args, insert here */
2287        doreplace = 0;
2288        break;  
2289     }
2290                  if (usedElements[i])                  if (usedElements[i])
2291                      continue;                      continue;
2292   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2293                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2294      break;      break;
2295                  }                  }
2296              }              }
     chptr = strchr(*arg, '=');  
2297    
2298      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2299   /* replace */   /* direct replacement */
2300   free(line->elements[i].item);   free(line->elements[i].item);
2301   line->elements[i].item = strdup(*arg);   line->elements[i].item = strdup(*arg);
     } else if (useRoot && !strncmp(*arg, "root=/dev/", 10) && *chptr) {  
  rootLine = entry->lines;  
  while (rootLine && rootLine->type != LT_ROOT)  
     rootLine = rootLine->next;  
  if (!rootLine) {  
     rootLine = addLine(entry, cfg->cfi, LT_ROOT, NULL, NULL);  
     rootLine->elements = realloc(rootLine->elements,  
     2 * sizeof(*rootLine->elements));  
     rootLine->numElements++;  
     rootLine->elements[1].indent = strdup("");  
     rootLine->elements[1].item = strdup("");  
  }  
2302    
2303   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2304   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2305      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2306   /* append */   if (rootLine) {
2307   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2308   (line->numElements + 1) * sizeof(*line->elements));      rootLine->elements[1].item = strdup(*arg + 5);
  line->elements[line->numElements].item = strdup(*arg);  
  usedElements = realloc(usedElements,  
  (line->numElements + 1) * sizeof(int));  
  usedElements[line->numElements] = 1;  
   
  if (line->numElements > 1) {  
     /* add to existing list of arguments */  
     line->elements[line->numElements].indent =  
  line->elements[line->numElements - 1].indent;  
     line->elements[line->numElements - 1].indent = strdup(" ");  
2309   } else {   } else {
2310      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2311         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2312   }   }
2313        }
2314    
2315   line->numElements++;      else {
2316     /* insert/append */
2317     insertElement(line, *arg, i, cfg->cfi);
2318     usedElements = realloc(usedElements, line->numElements *
2319           sizeof(*usedElements));
2320     memmove(&usedElements[i + 1], &usedElements[i],
2321     line->numElements - i - 1);
2322     usedElements[i] = 1;
2323    
2324   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2325     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2326     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2327   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2328      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2329      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2330   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2331   }   }
2332      }      }
             k++;  
2333   }   }
2334    
2335          free(usedElements);          free(usedElements);
2336    
  /* no arguments to remove (i.e. no append line) */  
  if (!line) continue;  
   
  /* this won't remove an LT_ROOT item properly (but then again,  
    who cares? */  
2337   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2338      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2339   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2340        !strcmp(line->elements[i].item, "--"))
2341        /* reached the end of hyper args, stop here */
2342        break;
2343     if (!argMatch(line->elements[i].item, *arg)) {
2344        removeElement(line, i);
2345      break;      break;
   
     if (i < line->numElements) {  
  /* if this isn't the first argument the previous argument  
    gets this arguments post-indention */  
  if (i > firstElement) {  
     free(line->elements[i - 1].indent);  
     line->elements[i - 1].indent = line->elements[i].indent;  
2346   }   }
2347        }
2348   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2349        if (useRoot && !strncmp(*arg, "root=", 5)) {
2350   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2351      line->elements[j - 1] = line->elements[j];   if (rootLine)
2352        removeLine(entry, rootLine);
  line->numElements--;  
2353      }      }
2354   }   }
2355    
# Line 1760  int updateActualImage(struct grubConfig Line 2360  int updateActualImage(struct grubConfig
2360   }   }
2361      }      }
2362    
     free(usedArgs);  
2363      free(newArgs);      free(newArgs);
2364      free(oldArgs);      free(oldArgs);
2365    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2385  int updateImage(struct grubConfig * cfg,
2385      return rc;      return rc;
2386  }  }
2387    
2388    int updateInitrd(struct grubConfig * cfg, const char * image,
2389                     const char * prefix, const char * initrd) {
2390        struct singleEntry * entry;
2391        struct singleLine * line, * kernelLine, *endLine = NULL;
2392        int index = 0;
2393    
2394        if (!image) return 0;
2395    
2396        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2397            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2398            if (!kernelLine) continue;
2399    
2400            line = getLineByType(LT_INITRD, entry->lines);
2401            if (line)
2402                removeLine(entry, line);
2403            if (prefix) {
2404                int prefixLen = strlen(prefix);
2405                if (!strncmp(initrd, prefix, prefixLen))
2406                    initrd += prefixLen;
2407            }
2408     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2409     if (endLine)
2410        removeLine(entry, endLine);
2411            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2412            if (!line)
2413        return 1;
2414     if (endLine) {
2415        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2416                if (!line)
2417     return 1;
2418     }
2419    
2420            break;
2421        }
2422    
2423        return 0;
2424    }
2425    
2426  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2427      int fd;      int fd;
2428      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1956  int checkForLilo(struct grubConfig * con Line 2593  int checkForLilo(struct grubConfig * con
2593      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2594  }  }
2595    
2596    int checkForGrub2(struct grubConfig * config) {
2597        if (!access("/etc/grub.d/", R_OK))
2598     return 2;
2599    
2600        return 1;
2601    }
2602    
2603  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2604      int fd;      int fd;
2605      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2620  int checkForGrub(struct grubConfig * con
2620      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2621   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2622   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2623     close(fd);
2624     return 1;
2625        }
2626        close(fd);
2627    
2628        return checkDeviceBootloader(boot, bootSect);
2629    }
2630    
2631    int checkForExtLinux(struct grubConfig * config) {
2632        int fd;
2633        unsigned char bootSect[512];
2634        char * boot;
2635        char executable[] = "/boot/extlinux/extlinux";
2636    
2637        printf("entered: checkForExtLinux()\n");
2638    
2639        if (parseSysconfigGrub(NULL, &boot))
2640     return 0;
2641    
2642        /* assume grub is not installed -- not an error condition */
2643        if (!boot)
2644     return 0;
2645    
2646        fd = open(executable, O_RDONLY);
2647        if (fd < 0)
2648     /* this doesn't exist if grub hasn't been installed */
2649     return 0;
2650    
2651        if (read(fd, bootSect, 512) != 512) {
2652     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2653     executable, strerror(errno));
2654   return 1;   return 1;
2655      }      }
2656      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2669  static char * getRootSpecifier(char * st
2669      return rootspec;      return rootspec;
2670  }  }
2671    
2672    static char * getInitrdVal(struct grubConfig * config,
2673       const char * prefix, struct singleLine *tmplLine,
2674       const char * newKernelInitrd,
2675       char ** extraInitrds, int extraInitrdCount)
2676    {
2677        char *initrdVal, *end;
2678        int i;
2679        size_t totalSize;
2680        size_t prefixLen;
2681        char separatorChar;
2682    
2683        prefixLen = strlen(prefix);
2684        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2685    
2686        for (i = 0; i < extraInitrdCount; i++) {
2687     totalSize += sizeof(separatorChar);
2688     totalSize += strlen(extraInitrds[i]) - prefixLen;
2689        }
2690    
2691        initrdVal = end = malloc(totalSize);
2692    
2693        end = stpcpy (end, newKernelInitrd + prefixLen);
2694    
2695        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2696        for (i = 0; i < extraInitrdCount; i++) {
2697     const char *extraInitrd;
2698     int j;
2699    
2700     extraInitrd = extraInitrds[i] + prefixLen;
2701     /* Don't add entries that are already there */
2702     if (tmplLine != NULL) {
2703        for (j = 2; j < tmplLine->numElements; j++)
2704     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2705        break;
2706    
2707        if (j != tmplLine->numElements)
2708     continue;
2709     }
2710    
2711     *end++ = separatorChar;
2712     end = stpcpy(end, extraInitrd);
2713        }
2714    
2715        return initrdVal;
2716    }
2717    
2718  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2719           const char * prefix,           const char * prefix,
2720   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2721   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2722     char ** extraInitrds, int extraInitrdCount,
2723                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2724      struct singleEntry * new;      struct singleEntry * new;
2725      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2726      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2727      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2728    
2729      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2730    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2754  int addNewKernel(struct grubConfig * con
2754      config->entries = new;      config->entries = new;
2755    
2756      /* copy/update from the template */      /* copy/update from the template */
2757      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2758        if (newKernelInitrd)
2759     needs |= NEED_INITRD;
2760      if (newMBKernel) {      if (newMBKernel) {
2761          needs |= KERNEL_MB;          needs |= NEED_MB;
2762          new->multiboot = 1;          new->multiboot = 1;
2763      }      }
2764    
2765      if (template) {      if (template) {
2766   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2767      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2768      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2769   indent = tmplLine->indent;   {
2770        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2771    
2772      /* skip comments */      /* skip comments */
2773      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2774      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2775      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2776    
2777      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2778      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2779     if (!template->multiboot && (needs & NEED_MB)) {
2780              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2781                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2782                  struct singleLine *l;       * hypervisor at the same time.
2783                  needs &= ~ KERNEL_MB;       */
2784        if (config->cfi->mbHyperFirst) {
2785                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2786                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2787                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2788                      newMBKernel + strlen(prefix));
2789                  tmplLine = lastLine;   /* set up for adding the kernel line */
2790                  if (!new->lines) {   free(tmplLine->indent);
2791                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2792                  } else {   needs &= ~NEED_MB;
2793                      newLine->next = l;      }
2794                      newLine = l;      if (needs & NEED_KERNEL) {
2795                  }   /* use addLineTmpl to preserve line elements,
2796                  continue;   * otherwise we could just call addLine.  Unfortunately
2797              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2798                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2799                  continue; /* don't need multiboot kernel here */   * change below.
2800              }   */
2801     struct keywordTypes * mbm_kw =
2802        getKeywordByType(LT_MBMODULE, config->cfi);
2803     if (mbm_kw) {
2804        tmplLine->type = LT_MBMODULE;
2805        free(tmplLine->elements[0].item);
2806        tmplLine->elements[0].item = strdup(mbm_kw->key);
2807     }
2808     newLine = addLineTmpl(new, tmplLine, newLine,
2809          newKernelPath + strlen(prefix), config->cfi);
2810     needs &= ~NEED_KERNEL;
2811        }
2812        if (needs & NEED_MB) { /* !mbHyperFirst */
2813     newLine = addLine(new, config->cfi, LT_HYPER,
2814      config->secondaryIndent,
2815      newMBKernel + strlen(prefix));
2816     needs &= ~NEED_MB;
2817        }
2818     } else if (needs & NEED_KERNEL) {
2819        newLine = addLineTmpl(new, tmplLine, newLine,
2820      newKernelPath + strlen(prefix), config->cfi);
2821        needs &= ~NEED_KERNEL;
2822     }
2823    
2824      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2825   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2826   new->lines = newLine;   if (needs & NEED_MB) {
2827      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2828   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2829   newLine = newLine->next;      needs &= ~NEED_MB;
2830      }   }
2831    
2832        } else if (tmplLine->type == LT_MBMODULE &&
2833           tmplLine->numElements >= 2) {
2834     if (new->multiboot) {
2835        if (needs & NEED_KERNEL) {
2836     newLine = addLineTmpl(new, tmplLine, newLine,
2837          newKernelPath +
2838          strlen(prefix), config->cfi);
2839     needs &= ~NEED_KERNEL;
2840        } else if (config->cfi->mbInitRdIsModule &&
2841           (needs & NEED_INITRD)) {
2842     char *initrdVal;
2843     initrdVal = getInitrdVal(config, prefix, tmplLine,
2844     newKernelInitrd, extraInitrds,
2845     extraInitrdCount);
2846     newLine = addLineTmpl(new, tmplLine, newLine,
2847          initrdVal, config->cfi);
2848     free(initrdVal);
2849     needs &= ~NEED_INITRD;
2850        }
2851     } else if (needs & NEED_KERNEL) {
2852        /* template is multi but new is not,
2853         * insert the kernel in the first module slot
2854         */
2855        tmplLine->type = LT_KERNEL;
2856        free(tmplLine->elements[0].item);
2857        tmplLine->elements[0].item =
2858     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2859        newLine = addLineTmpl(new, tmplLine, newLine,
2860      newKernelPath + strlen(prefix), config->cfi);
2861        needs &= ~NEED_KERNEL;
2862     } else if (needs & NEED_INITRD) {
2863        char *initrdVal;
2864        /* template is multi but new is not,
2865         * insert the initrd in the second module slot
2866         */
2867        tmplLine->type = LT_INITRD;
2868        free(tmplLine->elements[0].item);
2869        tmplLine->elements[0].item =
2870     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2871        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2872        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2873        free(initrdVal);
2874        needs &= ~NEED_INITRD;
2875     }
2876    
     newLine->indent = strdup(tmplLine->indent);  
     newLine->next = NULL;  
     newLine->type = tmplLine->type;  
     newLine->numElements = tmplLine->numElements;  
     newLine->elements = malloc(sizeof(*newLine->elements) *  
     newLine->numElements);  
     for (i = 0; i < newLine->numElements; i++) {  
  newLine->elements[i].item = strdup(tmplLine->elements[i].item);  
  newLine->elements[i].indent =  
  strdup(tmplLine->elements[i].indent);  
     }  
   
             lastLine = tmplLine;  
     if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {  
                 char * repl;  
                 if (!template->multiboot) {  
                     needs &= ~KERNEL_KERNEL;  
                     repl = newKernelPath;  
                 } else {  
                     needs &= ~KERNEL_MB;  
                     repl = newMBKernel;  
                 }  
                 if (new->multiboot && !template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("module");  
                     newLine->type = LT_MBMODULE;  
                 }  
  free(newLine->elements[1].item);  
                 rootspec = getRootSpecifier(tmplLine->elements[1].item);  
                 if (rootspec != NULL) {  
                     newLine->elements[1].item = sdupprintf("%s%s",  
                                                            rootspec,  
                                                            repl +  
                                                            strlen(prefix));  
                 } else {  
                     newLine->elements[1].item = strdup(repl +  
                                                        strlen(prefix));  
                 }  
             } else if (tmplLine->type == LT_MBMODULE &&  
                        tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {  
                 needs &= ~KERNEL_KERNEL;  
                 if (!new->multiboot && template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("kernel");  
                     newLine->type = LT_KERNEL;  
                 }  
  free(newLine->elements[1].item);  
                 rootspec = getRootSpecifier(tmplLine->elements[1].item);  
                 if (rootspec != NULL) {  
                     newLine->elements[1].item = sdupprintf("%s%s",  
                                                            rootspec,  
                                                            newKernelPath +  
                                                            strlen(prefix));  
                 } else {  
                     newLine->elements[1].item = strdup(newKernelPath +  
                                                        strlen(prefix));  
                 }  
2877      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2878      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2879   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2880   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2881                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2882                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2883                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2884                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2885                  }       */
2886                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2887                  if (rootspec != NULL) {   char *initrdVal;
2888                      newLine->elements[1].item = sdupprintf("%s%s",  
2889                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2890                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2891                                                             strlen(prefix));    config->secondaryIndent,
2892                  } else {    initrdVal);
2893                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2894                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2895                  }      }
2896              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2897                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2898   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2899                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2900                      free(newLine->elements[0].item);      free(initrdVal);
2901                      newLine->elements[0].item = strdup("initrd");      needs &= ~NEED_INITRD;
                     newLine->type = LT_INITRD;  
                 }  
  free(newLine->elements[1].item);  
                 rootspec = getRootSpecifier(tmplLine->elements[1].item);  
                 if (rootspec != NULL) {  
                     newLine->elements[1].item = sdupprintf("%s%s",  
                                                            rootspec,  
                                                            newKernelInitrd +  
                                                            strlen(prefix));  
                 } else {  
                     newLine->elements[1].item = strdup(newKernelInitrd +  
                                                        strlen(prefix));  
                 }  
     } else if (tmplLine->type == LT_TITLE &&  
     tmplLine->numElements >= 2) {  
  needs &= ~KERNEL_TITLE;  
   
  for (i = 1; i < newLine->numElements; i++) {  
     free(newLine->elements[i].item);  
     free(newLine->elements[i].indent);  
2902   }   }
2903    
2904   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
2905   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
2906   newLine->numElements = 2;   requote(tmplLine, config->cfi);
2907     char *nkt = malloc(strlen(newKernelTitle)+3);
2908     strcpy(nkt, "'");
2909     strcat(nkt, newKernelTitle);
2910     strcat(nkt, "'");
2911     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
2912     free(nkt);
2913     needs &= ~NEED_TITLE;
2914      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2915                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2916                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2917                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2918                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2919                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2920                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2921                                             newLine->numElements);     config->cfi->titleBracketed) {
2922        /* addLineTmpl doesn't handle titleBracketed */
2923                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2924                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2925                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2926                  newLine->numElements = 1;   }
2927              }      } else if (tmplLine->type == LT_ECHO) {
2928        requote(tmplLine, config->cfi);
2929        if (tmplLine->numElements > 1 &&
2930        strstr(tmplLine->elements[1].item, "'Loading Linux ")) {
2931     char *prefix = "'Loading ";
2932     char *newTitle = malloc(strlen(prefix) +
2933     strlen(newKernelTitle) + 2);
2934    
2935     strcpy(newTitle, prefix);
2936     strcat(newTitle, newKernelTitle);
2937     strcat(newTitle, "'");
2938     newLine = addLine(new, config->cfi, LT_ECHO,
2939     tmplLine->indent, newTitle);
2940     free(newTitle);
2941        } else {
2942     /* pass through other lines from the template */
2943     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
2944     config->cfi);
2945        }
2946        } else {
2947     /* pass through other lines from the template */
2948     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2949        }
2950   }   }
2951    
2952      } else {      } else {
2953   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2954      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2955     */
2956     switch (config->cfi->entryStart) {
2957        case LT_KERNEL:
2958     if (new->multiboot && config->cfi->mbHyperFirst) {
2959        /* fall through to LT_HYPER */
2960     } else {
2961        newLine = addLine(new, config->cfi, LT_KERNEL,
2962          config->primaryIndent,
2963          newKernelPath + strlen(prefix));
2964        needs &= ~NEED_KERNEL;
2965        break;
2966     }
2967    
2968        case LT_HYPER:
2969     newLine = addLine(new, config->cfi, LT_HYPER,
2970      config->primaryIndent,
2971      newMBKernel + strlen(prefix));
2972     needs &= ~NEED_MB;
2973   break;   break;
         }  
2974    
2975   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
2976      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
2977       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
2978       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
2979      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
2980       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
2981      default:        config->primaryIndent, nkt);
2982                  /* zipl strikes again */   free(nkt);
2983                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
2984                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
2985                      chptr = newKernelTitle;   break;
2986                      type = LT_TITLE;      }
2987                      break;      case LT_TITLE:
2988                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
2989                      abort();   char * templabel;
2990                  }   int x = 0, y = 0;
2991   }  
2992     templabel = strdup(newKernelTitle);
2993     while( templabel[x]){
2994     if( templabel[x] == ' ' ){
2995     y = x;
2996     while( templabel[y] ){
2997     templabel[y] = templabel[y+1];
2998     y++;
2999     }
3000     }
3001     x++;
3002     }
3003     newLine = addLine(new, config->cfi, LT_TITLE,
3004      config->primaryIndent, templabel);
3005     free(templabel);
3006     }else{
3007     newLine = addLine(new, config->cfi, LT_TITLE,
3008      config->primaryIndent, newKernelTitle);
3009     }
3010     needs &= ~NEED_TITLE;
3011     break;
3012    
3013   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3014   new->lines = newLine;   abort();
3015     }
3016      }      }
3017    
3018      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3019          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3020              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3021                                config->secondaryIndent,       */
3022                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3023          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3024              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3025                                config->secondaryIndent,    newKernelTitle);
3026                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3027          /* don't need to check for title as it's guaranteed to have been      }
3028           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3029           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3030          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3031              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3032                                config->secondaryIndent,   needs &= ~NEED_MB;
3033                                newKernelInitrd + strlen(prefix));      }
3034      } else {      if (needs & NEED_KERNEL) {
3035          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3036              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3037                                config->secondaryIndent,        config->cfi)) ?
3038                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3039          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3040              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3041                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3042                                newKernelTitle);      }
3043          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3044              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3045                                config->secondaryIndent,    config->secondaryIndent,
3046                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3047     needs &= ~NEED_MB;
3048        }
3049        if (needs & NEED_INITRD) {
3050     char *initrdVal;
3051     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3052     newLine = addLine(new, config->cfi,
3053      (new->multiboot && getKeywordByType(LT_MBMODULE,
3054          config->cfi)) ?
3055      LT_MBMODULE : LT_INITRD,
3056      config->secondaryIndent,
3057      initrdVal);
3058     free(initrdVal);
3059     needs &= ~NEED_INITRD;
3060        }
3061        if (needs & NEED_END) {
3062     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3063     config->secondaryIndent, NULL);
3064     needs &= ~NEED_END;
3065        }
3066    
3067        if (needs) {
3068     printf(_("grubby: needs=%d, aborting\n"), needs);
3069     abort();
3070      }      }
3071    
3072      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3075  int addNewKernel(struct grubConfig * con
3075      return 0;      return 0;
3076  }  }
3077    
3078    static void traceback(int signum)
3079    {
3080        void *array[40];
3081        size_t size;
3082    
3083        signal(SIGSEGV, SIG_DFL);
3084        memset(array, '\0', sizeof (array));
3085        size = backtrace(array, 40);
3086    
3087        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3088                (unsigned long)size);
3089        backtrace_symbols_fd(array, size, STDERR_FILENO);
3090        exit(1);
3091    }
3092    
3093  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3094      poptContext optCon;      poptContext optCon;
3095      char * grubConfig = NULL;      const char * grubConfig = NULL;
3096      char * outputFile = NULL;      char * outputFile = NULL;
3097      int arg = 0;      int arg = 0;
3098      int flags = 0;      int flags = 0;
3099      int badImageOkay = 0;      int badImageOkay = 0;
3100        int configureGrub2 = 0;
3101      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3102      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3103        int configureExtLinux = 0;
3104      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3105        int extraInitrdCount = 0;
3106      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3107      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3108      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3118  int main(int argc, const char ** argv) {
3118      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3119      char * removeArgs = NULL;      char * removeArgs = NULL;
3120      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3121        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3122      const char * chptr = NULL;      const char * chptr = NULL;
3123      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3124      struct grubConfig * config;      struct grubConfig * config;
# Line 2339  int main(int argc, const char ** argv) { Line 3159  int main(int argc, const char ** argv) {
3159      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3160   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3161      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3162     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3163        _("configure extlinux bootloader (from syslinux)") },
3164   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3165      _("configure grub bootloader") },      _("configure grub bootloader") },
3166     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3167        _("configure grub2 bootloader") },
3168   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3169      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3170      _("kernel-path") },      _("kernel-path") },
3171   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3172      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3173     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3174        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3175   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3176      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3177   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3208  int main(int argc, const char ** argv) {
3208   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3209      };      };
3210    
3211        useextlinuxmenu=0;
3212    
3213        signal(SIGSEGV, traceback);
3214    
3215      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3216      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3217    
# Line 2391  int main(int argc, const char ** argv) { Line 3221  int main(int argc, const char ** argv) {
3221      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3222      exit(0);      exit(0);
3223      break;      break;
3224      case 'i':
3225        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3226         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3227        } else {
3228     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3229     return 1;
3230        }
3231        break;
3232   }   }
3233      }      }
3234    
# Line 2406  int main(int argc, const char ** argv) { Line 3244  int main(int argc, const char ** argv) {
3244   return 1;   return 1;
3245      }      }
3246    
3247      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3248   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3249     configureExtLinux ) > 1) {
3250   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3251   return 1;   return 1;
3252      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3253   fprintf(stderr,   fprintf(stderr,
3254      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3255   return 1;   return 1;
3256        } else if (configureGrub2) {
3257     cfi = &grub2ConfigType;
3258      } else if (configureLilo) {      } else if (configureLilo) {
3259   cfi = &liloConfigType;   cfi = &liloConfigType;
3260      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3267  int main(int argc, const char ** argv) {
3267          cfi = &siloConfigType;          cfi = &siloConfigType;
3268      } else if (configureZipl) {      } else if (configureZipl) {
3269          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3270        } else if (configureExtLinux) {
3271     cfi = &extlinuxConfigType;
3272     useextlinuxmenu=1;
3273      }      }
3274    
3275      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3284  int main(int argc, const char ** argv) {
3284        #elif __s390x__        #elif __s390x__
3285          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3286        #else        #else
3287   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3288        cfi = &grub2ConfigType;
3289     else
3290        cfi = &grubConfigType;
3291        #endif        #endif
3292      }      }
3293    
3294      if (!grubConfig)      if (!grubConfig) {
3295   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3296        grubConfig = cfi->findConfig(cfi);
3297     if (!grubConfig)
3298        grubConfig = cfi->defaultConfig;
3299        }
3300    
3301      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3302    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
# Line 2465  int main(int argc, const char ** argv) { Line 3316  int main(int argc, const char ** argv) {
3316      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3317   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3318   return 1;   return 1;
3319      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3320    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3321    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3322   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3323   return 1;   return 1;
3324      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3371  int main(int argc, const char ** argv) {
3371   bootPrefix = "";   bootPrefix = "";
3372      }      }
3373    
3374        if (!cfi->mbAllowExtraInitRds &&
3375     extraInitrdCount > 0) {
3376     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3377     return 1;
3378        }
3379    
3380      if (bootloaderProbe) {      if (bootloaderProbe) {
3381   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3382   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3383    
3384     const char *grub2config = grub2FindConfig(&grub2ConfigType);
3385     if (grub2config) {
3386        gconfig = readConfig(grub2config, &grub2ConfigType);
3387        if (!gconfig)
3388     gr2c = 1;
3389        else
3390     gr2c = checkForGrub2(gconfig);
3391     }
3392    
3393   if (!access(grubConfigType.defaultConfig, F_OK)) {   if (!access(grubConfigType.defaultConfig, F_OK)) {
3394      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);
3395      if (!gconfig)      if (!gconfig)
# Line 2540  int main(int argc, const char ** argv) { Line 3406  int main(int argc, const char ** argv) {
3406   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3407   }   }
3408    
3409   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3410        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3411        if (!lconfig)
3412     erc = 1;
3413        else
3414     erc = checkForExtLinux(lconfig);
3415     }
3416    
3417     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3418    
3419   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3420     if (gr2c == 2) printf("grub2\n");
3421   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3422     if (erc == 2) printf("extlinux\n");
3423    
3424   return 0;   return 0;
3425      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3437  int main(int argc, const char ** argv) {
3437   if (!entry) return 0;   if (!entry) return 0;
3438   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3439    
3440   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3441   if (!line) return 0;   if (!line) return 0;
3442    
3443          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2585  int main(int argc, const char ** argv) { Line 3460  int main(int argc, const char ** argv) {
3460      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3461      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3462                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3463        if (updateKernelPath && newKernelInitrd) {
3464                if (updateInitrd(config, updateKernelPath, bootPrefix,
3465                                 newKernelInitrd)) return 1;
3466        }
3467      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3468                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3469                         extraInitrds, extraInitrdCount,
3470                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3471            
3472    
# Line 2597  int main(int argc, const char ** argv) { Line 3477  int main(int argc, const char ** argv) {
3477      }      }
3478    
3479      if (!outputFile)      if (!outputFile)
3480   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3481    
3482      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3483  }  }

Legend:
Removed from v.532  
changed lines
  Added in v.1714