Magellan Linux

Diff of /tags/grubby-8_2/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 tags/grubby-8_2/grubby.c revision 1709 by niro, Sat Feb 18 00:24:28 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    
194        if (i == -1) {
195     for (i = 0; configFiles[i] != NULL; i++) {
196        dbgPrintf("Checking \"%s\": ", configFiles[i]);
197        if (!access(configFiles[i], R_OK)) {
198     dbgPrintf("found\n");
199     return configFiles[i];
200        }
201        dbgPrintf("not found\n");
202     }
203        }
204        return configFiles[i];
205    }
206    
207    struct configFileInfo grub2ConfigType = {
208        .findConfig = grub2FindConfig,
209        .keywords = grub2Keywords,
210        .defaultIsIndex = 1,
211        .defaultSupportSaved = 0,
212        .defaultIsVariable = 1,
213        .entryStart = LT_MENUENTRY,
214        .entryEnd = LT_ENTRY_END,
215        .titlePosition = 1,
216        .needsBootPrefix = 1,
217        .mbHyperFirst = 1,
218        .mbInitRdIsModule = 1,
219        .mbAllowExtraInitRds = 1,
220  };  };
221    
222  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 250  struct keywordTypes yabootKeywords[] = {
250      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
251      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
252      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
253      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
254      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
255      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
256      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 270  struct keywordTypes liloKeywords[] = {
270      { NULL,    0, 0 },      { NULL,    0, 0 },
271  };  };
272    
273    struct keywordTypes eliloKeywords[] = {
274        { "label",    LT_TITLE,    '=' },
275        { "root",    LT_ROOT,    '=' },
276        { "default",    LT_DEFAULT,    '=' },
277        { "image",    LT_KERNEL,    '=' },
278        { "initrd",    LT_INITRD,    '=' },
279        { "append",    LT_KERNELARGS,  '=' },
280        { "vmm",    LT_HYPER,       '=' },
281        { NULL,    0, 0 },
282    };
283    
284  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
285      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
286      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 302  struct keywordTypes ziplKeywords[] = {
302      { NULL,         0, 0 },      { NULL,         0, 0 },
303  };  };
304    
305    struct keywordTypes extlinuxKeywords[] = {
306        { "label",    LT_TITLE,    ' ' },
307        { "root",    LT_ROOT,    ' ' },
308        { "default",    LT_DEFAULT,    ' ' },
309        { "kernel",    LT_KERNEL,    ' ' },
310        { "initrd",    LT_INITRD,      ' ', ',' },
311        { "append",    LT_KERNELARGS,  ' ' },
312        { "prompt",     LT_UNKNOWN,     ' ' },
313        { NULL,    0, 0 },
314    };
315    int useextlinuxmenu;
316  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
317      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
318      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
319      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
320      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
321      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
322      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
323  };  };
324    
325  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
326      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
327      liloKeywords,    /* keywords */      .keywords = liloKeywords,
328      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
329      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
330      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
331  };  };
332    
333  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
334      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
335      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
336      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
337      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
338      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
339      1,    /* needsBootPrefix */      .maxTitleLength = 15,
340      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
341  };  };
342    
343  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
344      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
345      siloKeywords,    /* keywords */      .keywords = siloKeywords,
346      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
347      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
348      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
349      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
350  };  };
351    
352  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
353      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
354      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
355      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
356      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
357      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
358      0,    /* needsBootPrefix */  };
359      1,    /* argsInQuotes */  
360      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
361      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
362        .keywords = extlinuxKeywords,
363        .entryStart = LT_TITLE,
364        .needsBootPrefix = 1,
365        .maxTitleLength = 255,
366        .mbAllowExtraInitRds = 1,
367  };  };
368    
369  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 378  struct grubConfig {
378      struct configFileInfo * cfi;      struct configFileInfo * cfi;
379  };  };
380    
381    blkid_cache blkid;
382    
383  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
384  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
385       const char * path, const char * prefix,       const char * path, const char * prefix,
386       int * index);       int * index);
 static char * strndup(char * from, int len);  
387  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
388  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
389    struct singleLine * lineDup(struct singleLine * line);
390  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
391  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
392       struct configFileInfo * cfi);       struct configFileInfo * cfi);
393  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
394         struct configFileInfo * cfi);         struct configFileInfo * cfi);
395  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
396    static void requote(struct singleLine *line, struct configFileInfo * cfi);
397  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
398      char * to;    const char * item, int insertHere,
399      struct configFileInfo * cfi);
400      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
401      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
402      to[len] = '\0';        struct configFileInfo * cfi);
403    static enum lineType_e getTypeByKeyword(char * keyword,
404      return to;   struct configFileInfo * cfi);
405  }  static struct singleLine * getLineByType(enum lineType_e type,
406     struct singleLine * line);
407    static int checkForExtLinux(struct grubConfig * config);
408    struct singleLine * addLineTmpl(struct singleEntry * entry,
409                                    struct singleLine * tmplLine,
410                                    struct singleLine * prevLine,
411                                    const char * val,
412     struct configFileInfo * cfi);
413    struct singleLine *  addLine(struct singleEntry * entry,
414                                 struct configFileInfo * cfi,
415                                 enum lineType_e type, char * defaultIndent,
416                                 const char * val);
417    
418  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
419  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 448  static char * sdupprintf(const char *for
448      return buf;      return buf;
449  }  }
450    
451    static struct keywordTypes * getKeywordByType(enum lineType_e type,
452          struct configFileInfo * cfi) {
453        struct keywordTypes * kw;
454        for (kw = cfi->keywords; kw->key; kw++) {
455     if (kw->type == type)
456        return kw;
457        }
458        return NULL;
459    }
460    
461    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
462        struct keywordTypes *kt = getKeywordByType(type, cfi);
463        if (kt)
464     return kt->key;
465        return "unknown";
466    }
467    
468    static char * getpathbyspec(char *device) {
469        if (!blkid)
470            blkid_get_cache(&blkid, NULL);
471    
472        return blkid_get_devname(blkid, device, NULL);
473    }
474    
475    static char * getuuidbydev(char *device) {
476        if (!blkid)
477     blkid_get_cache(&blkid, NULL);
478    
479        return blkid_get_tag_value(blkid, "UUID", device);
480    }
481    
482    static enum lineType_e getTypeByKeyword(char * keyword,
483     struct configFileInfo * cfi) {
484        struct keywordTypes * kw;
485        for (kw = cfi->keywords; kw->key; kw++) {
486     if (!strcmp(keyword, kw->key))
487        return kw->type;
488        }
489        return LT_UNKNOWN;
490    }
491    
492    static struct singleLine * getLineByType(enum lineType_e type,
493     struct singleLine * line) {
494        dbgPrintf("getLineByType(%d): ", type);
495        for (; line; line = line->next) {
496     dbgPrintf("%d:%s ", line->type,
497      line->numElements ? line->elements[0].item : "(empty)");
498     if (line->type & type) break;
499        }
500        dbgPrintf(line ? "\n" : " (failed)\n");
501        return line;
502    }
503    
504  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
505      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
506          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
507          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
508              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 514  static int isBracketedTitle(struct singl
514      return 0;      return 0;
515  }  }
516    
517  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
518                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
519      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
520   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;  
521  }  }
522    
523  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 568  static void lineInit(struct singleLine *
568      line->next = NULL;      line->next = NULL;
569  }  }
570    
571    struct singleLine * lineDup(struct singleLine * line) {
572        int i;
573        struct singleLine * newLine = malloc(sizeof(*newLine));
574    
575        newLine->indent = strdup(line->indent);
576        newLine->next = NULL;
577        newLine->type = line->type;
578        newLine->numElements = line->numElements;
579        newLine->elements = malloc(sizeof(*newLine->elements) *
580           newLine->numElements);
581    
582        for (i = 0; i < newLine->numElements; i++) {
583     newLine->elements[i].indent = strdup(line->elements[i].indent);
584     newLine->elements[i].item = strdup(line->elements[i].item);
585        }
586    
587        return newLine;
588    }
589    
590  static void lineFree(struct singleLine * line) {  static void lineFree(struct singleLine * line) {
591      int i;      int i;
592    
# Line 414  static int lineWrite(FILE * out, struct Line 612  static int lineWrite(FILE * out, struct
612      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
613    
614   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
615   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
616        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
617      }      }
618    
619      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 632  static int getNextLine(char ** bufPtr, s
632      char * chptr;      char * chptr;
633      int elementsAlloced = 0;      int elementsAlloced = 0;
634      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
635      int first = 1;      int first = 1;
     int i;  
636    
637      lineFree(line);      lineFree(line);
638    
# Line 489  static int getNextLine(char ** bufPtr, s Line 686  static int getNextLine(char ** bufPtr, s
686      if (!line->numElements)      if (!line->numElements)
687   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
688      else {      else {
689   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
690      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;  
               
691              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
692               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
693              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 532  static int getNextLine(char ** bufPtr, s Line 723  static int getNextLine(char ** bufPtr, s
723   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
724   line->numElements = 0;   line->numElements = 0;
725      }      }
726     } else {
727     struct keywordTypes *kw;
728    
729     kw = getKeywordByType(line->type, cfi);
730    
731     /* space isn't the only separator, we need to split
732     * elements up more
733     */
734     if (!isspace(kw->separatorChar)) {
735        int i;
736        char indent[2] = "";
737        indent[0] = kw->separatorChar;
738        for (i = 1; i < line->numElements; i++) {
739     char *p;
740     int j;
741     int numNewElements;
742    
743     numNewElements = 0;
744     p = line->elements[i].item;
745     while (*p != '\0') {
746     if (*p == kw->separatorChar)
747     numNewElements++;
748     p++;
749     }
750     if (line->numElements + numNewElements >= elementsAlloced) {
751     elementsAlloced += numNewElements + 5;
752     line->elements = realloc(line->elements,
753        sizeof(*line->elements) * elementsAlloced);
754     }
755    
756     for (j = line->numElements; j > i; j--) {
757     line->elements[j + numNewElements] = line->elements[j];
758     }
759     line->numElements += numNewElements;
760    
761     p = line->elements[i].item;
762     while (*p != '\0') {
763    
764     while (*p != kw->separatorChar && *p != '\0') p++;
765     if (*p == '\0') {
766     break;
767     }
768    
769     free(line->elements[i].indent);
770     line->elements[i].indent = strdup(indent);
771     *p++ = '\0';
772     i++;
773     line->elements[i].item = strdup(p);
774     line->elements[i].indent = strdup("");
775     p = line->elements[i].item;
776     }
777        }
778     }
779   }   }
780      }      }
781    
# Line 595  static struct grubConfig * readConfig(co Line 839  static struct grubConfig * readConfig(co
839      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
840   }   }
841    
842   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi)) {
843      sawEntry = 1;      sawEntry = 1;
844      if (!entry) {      if (!entry) {
845   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 855  static struct grubConfig * readConfig(co
855      entry->next = NULL;      entry->next = NULL;
856   }   }
857    
858   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
859        int i;
860        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
861        dbgPrintf("%s", line->indent);
862        for (i = 0; i < line->numElements; i++)
863     dbgPrintf("%s\"%s\"", line->elements[i].indent, line->elements[i].item);
864        dbgPrintf("\n");
865        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
866        if (kwType && line->numElements == 3 &&
867        !strcmp(line->elements[1].item, kwType->key)) {
868     dbgPrintf("Line sets default config\n");
869     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
870     defaultLine = line;
871        }
872     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
873      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
874      defaultLine = line;      defaultLine = line;
875    
876            } else if (line->type == LT_KERNEL) {
877        /* if by some freak chance this is multiboot and the "module"
878         * lines came earlier in the template, make sure to use LT_HYPER
879         * instead of LT_KERNEL now
880         */
881        if (entry->multiboot)
882     line->type = LT_HYPER;
883    
884          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
885        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
886         * instead, now that we know this is a multiboot entry.
887         * This only applies to grub, but that's the only place we
888         * should find LT_MBMODULE lines anyway.
889         */
890        struct singleLine * l;
891        for (l = entry->lines; l; l = l->next) {
892     if (l->type == LT_HYPER)
893        break;
894     else if (l->type == LT_KERNEL) {
895        l->type = LT_HYPER;
896        break;
897     }
898        }
899              entry->multiboot = 1;              entry->multiboot = 1;
900    
901     } else if (line->type == LT_HYPER) {
902        entry->multiboot = 1;
903    
904   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
905      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
906      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
907    
908   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
909      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
910      len = 0;      len = 0;
# Line 643  static struct grubConfig * readConfig(co Line 929  static struct grubConfig * readConfig(co
929      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
930      line->elements[1].item = buf;      line->elements[1].item = buf;
931      line->numElements = 2;      line->numElements = 2;
932    
933   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
934      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
935         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 939  static struct grubConfig * readConfig(co
939   int last, len;   int last, len;
940    
941   if (*line->elements[1].item == '"')   if (*line->elements[1].item == '"')
942      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
943     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
944    
945   last = line->numElements - 1;   last = line->numElements - 1;
946   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
947   if (line->elements[last].item[len] == '"')   if (line->elements[last].item[len] == '"')
948      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
949      }      }
   
950   }   }
951    
952   /* 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 966  static struct grubConfig * readConfig(co
966   movedLine = 1;   movedLine = 1;
967   continue; /* without setting 'last' */   continue; /* without setting 'last' */
968   }   }
969    
970   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
971     which was moved, drop it. */     which was moved, drop it. */
972   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 982  static struct grubConfig * readConfig(co
982   entry->lines = line;   entry->lines = line;
983      else      else
984   last->next = line;   last->next = line;
985        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
986    
987        /* we could have seen this outside of an entry... if so, we
988         * ignore it like any other line we don't grok */
989        if (line->type == LT_ENTRY_END && sawEntry)
990     sawEntry = 0;
991   } else {   } else {
992      if (!cfg->theLines)      if (!cfg->theLines)
993   cfg->theLines = line;   cfg->theLines = line;
994      else {      else
995   last->next = line;   last->next = line;
996      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
997   }   }
998    
999   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1001  static struct grubConfig * readConfig(co
1001    
1002      free(incoming);      free(incoming);
1003    
1004        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1005      if (defaultLine) {      if (defaultLine) {
1006   if (cfi->defaultSupportSaved &&   if (cfi->defaultIsVariable) {
1007        char *value = defaultLine->elements[2].item;
1008        while (*value && (*value == '"' || *value == '\'' ||
1009        *value == ' ' || *value == '\t'))
1010     value++;
1011        cfg->defaultImage = strtol(value, &end, 10);
1012        while (*end && (*end == '"' || *end == '\'' ||
1013        *end == ' ' || *end == '\t'))
1014     end++;
1015        if (*end) cfg->defaultImage = -1;
1016     } else if (cfi->defaultSupportSaved &&
1017   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1018      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1019   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
# Line 730  static struct grubConfig * readConfig(co Line 1034  static struct grubConfig * readConfig(co
1034                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1035                  }                  }
1036   i++;   i++;
1037     entry = NULL;
1038      }      }
1039    
1040      if (entry) cfg->defaultImage = i;      if (entry){
1041            cfg->defaultImage = i;
1042        }else{
1043            cfg->defaultImage = -1;
1044        }
1045   }   }
1046        } else {
1047            cfg->defaultImage = 0;
1048      }      }
1049    
1050      return cfg;      return cfg;
# Line 751  static void writeDefault(FILE * out, cha Line 1062  static void writeDefault(FILE * out, cha
1062   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1063      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1064   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1065      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1066      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1067     cfg->defaultImage);
1068        } else {
1069     fprintf(out, "%sdefault%s%d\n", indent, separator,
1070     cfg->defaultImage);
1071        }
1072   } else {   } else {
1073      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1074    
# Line 769  static void writeDefault(FILE * out, cha Line 1085  static void writeDefault(FILE * out, cha
1085    
1086      if (!entry) return;      if (!entry) return;
1087    
1088      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1089    
1090      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1091   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1119  static int writeConfig(struct grubConfig
1119      int rc;      int rc;
1120    
1121      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1122         directory to / */         directory to the dir of the symlink */
1123      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1124      do {      do {
1125   buf = alloca(len + 1);   buf = alloca(len + 1);
1126   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1127   if (rc == len) len += 256;   if (rc == len) len += 256;
1128      } while (rc == len);      } while (rc == len);
1129            
# Line 843  static int writeConfig(struct grubConfig Line 1158  static int writeConfig(struct grubConfig
1158      }      }
1159    
1160      line = cfg->theLines;      line = cfg->theLines;
1161        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1162      while (line) {      while (line) {
1163   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1164     line->numElements == 3 &&
1165     !strcmp(line->elements[1].item, defaultKw->key)) {
1166        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1167        needs &= ~MAIN_DEFAULT;
1168     } else if (line->type == LT_DEFAULT) {
1169      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1170      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1171   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1233  static int numEntries(struct grubConfig
1233      return i;      return i;
1234  }  }
1235    
1236    static char *findDiskForRoot()
1237    {
1238        int fd;
1239        char buf[65536];
1240        char *devname;
1241        char *chptr;
1242        int rc;
1243    
1244        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1245            fprintf(stderr, "grubby: failed to open %s: %s\n",
1246                    _PATH_MOUNTED, strerror(errno));
1247            return NULL;
1248        }
1249    
1250        rc = read(fd, buf, sizeof(buf) - 1);
1251        if (rc <= 0) {
1252            fprintf(stderr, "grubby: failed to read %s: %s\n",
1253                    _PATH_MOUNTED, strerror(errno));
1254            close(fd);
1255            return NULL;
1256        }
1257        close(fd);
1258        buf[rc] = '\0';
1259        chptr = buf;
1260    
1261        while (chptr && chptr != buf+rc) {
1262            devname = chptr;
1263    
1264            /*
1265             * The first column of a mtab entry is the device, but if the entry is a
1266             * special device it won't start with /, so move on to the next line.
1267             */
1268            if (*devname != '/') {
1269                chptr = strchr(chptr, '\n');
1270                if (chptr)
1271                    chptr++;
1272                continue;
1273            }
1274    
1275            /* Seek to the next space */
1276            chptr = strchr(chptr, ' ');
1277            if (!chptr) {
1278                fprintf(stderr, "grubby: error parsing %s: %s\n",
1279                        _PATH_MOUNTED, strerror(errno));
1280                return NULL;
1281            }
1282    
1283            /*
1284             * The second column of a mtab entry is the mount point, we are looking
1285             * for '/' obviously.
1286             */
1287            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1288                /*
1289                 * Move back 2, which is the first space after the device name, set
1290                 * it to \0 so strdup will just get the devicename.
1291                 */
1292                chptr -= 2;
1293                *chptr = '\0';
1294                return strdup(devname);
1295            }
1296    
1297            /* Next line */
1298            chptr = strchr(chptr, '\n');
1299            if (chptr)
1300                chptr++;
1301        }
1302    
1303        return NULL;
1304    }
1305    
1306  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1307    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1308      struct singleLine * line;      struct singleLine * line;
1309      char * fullName;      char * fullName;
1310      int i;      int i;
     struct stat sb, sb2;  
1311      char * dev;      char * dev;
     char * end;  
1312      char * rootspec;      char * rootspec;
1313        char * rootdev;
1314    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
       
     if (!line) return 0;  
1315      if (skipRemoved && entry->skip) return 0;      if (skipRemoved && entry->skip) return 0;
1316      if (line->numElements < 2) return 0;  
1317        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1318        if (!line || line->numElements < 2) return 0;
1319    
1320      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1321    
# Line 935  int suitableImage(struct singleEntry * e Line 1323  int suitableImage(struct singleEntry * e
1323        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1324      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1325      sprintf(fullName, "%s%s", bootPrefix,      sprintf(fullName, "%s%s", bootPrefix,
1326              line->elements[1].item + ((rootspec != NULL) ?              line->elements[1].item + (rootspec ? strlen(rootspec) : 0));
                                       strlen(rootspec) : 0));  
1327      if (access(fullName, R_OK)) return 0;      if (access(fullName, R_OK)) return 0;
1328    
1329      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
# Line 945  int suitableImage(struct singleEntry * e Line 1332  int suitableImage(struct singleEntry * e
1332   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1333      } else {      } else {
1334   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1335   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1336    
1337   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1338      dev = line->elements[1].item;      dev = line->elements[1].item;
1339   } else {   } else {
1340              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1341      /* 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.
1342      line = entry->lines;       */
1343        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1344    
1345              /* failed to find one */              /* failed to find one */
1346              if (!line) return 0;              if (!line) return 0;
# Line 973  int suitableImage(struct singleEntry * e Line 1356  int suitableImage(struct singleEntry * e
1356   }   }
1357      }      }
1358    
1359      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1360   dev += 6;      if (!dev)
1361            return 0;
1362   /* check which device has this label */  
1363   dev = get_spec_by_volume_label(dev, &i, &i);      rootdev = findDiskForRoot();
1364   if (!dev) return 0;      if (!rootdev)
1365     return 0;
1366    
1367        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1368            free(rootdev);
1369            return 0;
1370      }      }
1371    
1372      if (*dev == '/') {      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1373   if (stat(dev, &sb))   free(rootdev);
1374      return 0;          return 0;
     } else {  
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1375      }      }
     stat("/", &sb2);  
1376    
1377      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1378    
1379      return 1;      return 1;
1380  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1418  struct singleEntry * findEntryByPath(str
1418   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1419   if (!entry) return NULL;   if (!entry) return NULL;
1420    
1421   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1422   if (!line) return NULL;   if (!line) return NULL;
1423    
1424   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1079  struct singleEntry * findEntryByPath(str Line 1460  struct singleEntry * findEntryByPath(str
1460      kernel += 6;      kernel += 6;
1461   }   }
1462    
1463   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1464      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1465    
1466        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1467    
1468      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1469                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1470          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1471                              ((rootspec != NULL) ? strlen(rootspec) : 0),       LT_KERNEL|LT_MBMODULE|LT_HYPER :
1472                              kernel + strlen(prefix)))       checkType, line);
1473                      break;   if (!line) break;  /* not found in this entry */
1474              }  
1475                 if (line && line->numElements >= 2) {
1476              /* have to check multiboot lines too */      rootspec = getRootSpecifier(line->elements[1].item);
1477              if (entry->multiboot) {      if (!strcmp(line->elements[1].item +
1478                  while (line && line->type != LT_MBMODULE) line = line->next;   ((rootspec != NULL) ? strlen(rootspec) : 0),
1479                  if (line && line->numElements >= 2 && !entry->skip) {   kernel + strlen(prefix)))
1480                      rootspec = getRootSpecifier(line->elements[1].item);   break;
1481                      if (!strcmp(line->elements[1].item  +   }
1482                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      }
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1483    
1484      i++;      /* make sure this entry has a kernel identifier; this skips
1485         * non-Linux boot entries (could find netbsd etc, though, which is
1486         * unfortunate)
1487         */
1488        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1489     break; /* found 'im! */
1490   }   }
1491    
1492   if (index) *index = i;   if (index) *index = i;
1493      }      }
1494    
     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);  
     }  
   
1495      return entry;      return entry;
1496  }  }
1497    
# Line 1286  void displayEntry(struct singleEntry * e Line 1656  void displayEntry(struct singleEntry * e
1656      char * root = NULL;      char * root = NULL;
1657      int i;      int i;
1658    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1659      printf("index=%d\n", index);      printf("index=%d\n", index);
1660    
1661        line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1662        if (!line) {
1663            printf("non linux entry\n");
1664            return;
1665        }
1666    
1667      printf("kernel=%s\n", line->elements[1].item);      printf("kernel=%s\n", line->elements[1].item);
1668    
1669      if (line->numElements >= 3) {      if (line->numElements >= 3) {
# Line 1308  void displayEntry(struct singleEntry * e Line 1681  void displayEntry(struct singleEntry * e
1681   }   }
1682   printf("\"\n");   printf("\"\n");
1683      } else {      } else {
1684   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1685   if (line) {   if (line) {
1686      char * s;      char * s;
1687    
# Line 1334  void displayEntry(struct singleEntry * e Line 1705  void displayEntry(struct singleEntry * e
1705      }      }
1706    
1707      if (!root) {      if (!root) {
1708   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1709   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
1710      root=line->elements[1].item;      root=line->elements[1].item;
1711      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 1720  void displayEntry(struct singleEntry * e
1720   printf("root=%s\n", s);   printf("root=%s\n", s);
1721      }      }
1722    
1723      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
1724    
1725      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
1726   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 1737  int parseSysconfigGrub(int * lbaPtr, cha
1737      char * start;      char * start;
1738      char * param;      char * param;
1739    
1740      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
1741      if (!in) return 1;      if (!in) return 1;
1742    
1743      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 1799  int displayInfo(struct grubConfig * conf
1799   return 1;   return 1;
1800      }      }
1801    
1802      /* 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
1803         be a better way */         be a better way */
1804      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
1805   dumpSysconfigGrub();   dumpSysconfigGrub();
1806      } else {      } else {
1807   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
1808   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
1809      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
1810   }   }
1811    
1812   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
1813   if (line) printf("lba\n");   if (line) printf("lba\n");
1814      }      }
1815    
# Line 1458  int displayInfo(struct grubConfig * conf Line 1824  int displayInfo(struct grubConfig * conf
1824      return 0;      return 0;
1825  }  }
1826    
1827    struct singleLine * addLineTmpl(struct singleEntry * entry,
1828     struct singleLine * tmplLine,
1829     struct singleLine * prevLine,
1830     const char * val,
1831     struct configFileInfo * cfi)
1832    {
1833        struct singleLine * newLine = lineDup(tmplLine);
1834    
1835        if (val) {
1836     /* override the inherited value with our own.
1837     * This is a little weak because it only applies to elements[1]
1838     */
1839     if (newLine->numElements > 1)
1840        removeElement(newLine, 1);
1841     insertElement(newLine, val, 1, cfi);
1842    
1843     /* but try to keep the rootspec from the template... sigh */
1844     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
1845        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
1846        if (rootspec != NULL) {
1847     free(newLine->elements[1].item);
1848     newLine->elements[1].item =
1849        sdupprintf("%s%s", rootspec, val);
1850        }
1851     }
1852        }
1853    
1854        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
1855          newLine->elements[0].item : "");
1856    
1857        if (!entry->lines) {
1858     /* first one on the list */
1859     entry->lines = newLine;
1860        } else if (prevLine) {
1861     /* add after prevLine */
1862     newLine->next = prevLine->next;
1863     prevLine->next = newLine;
1864        }
1865    
1866        return newLine;
1867    }
1868    
1869  /* val may be NULL */  /* val may be NULL */
1870  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
1871       struct configFileInfo * cfi,       struct configFileInfo * cfi,
1872       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
1873       char * val) {       const char * val) {
1874      struct singleLine * line, * prev;      struct singleLine * line, * prev;
1875      int i;      struct keywordTypes * kw;
1876        struct singleLine tmpl;
1877    
1878      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
1879   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
1880      if (type != LT_TITLE || !cfi->titleBracketed)       */
1881          if (!cfi->keywords[i].key) abort();  
1882        if (type == LT_TITLE && cfi->titleBracketed) {
1883     /* we're doing a bracketed title (zipl) */
1884     tmpl.type = type;
1885     tmpl.numElements = 1;
1886     tmpl.elements = alloca(sizeof(*tmpl.elements));
1887     tmpl.elements[0].item = alloca(strlen(val)+3);
1888     sprintf(tmpl.elements[0].item, "[%s]", val);
1889     tmpl.elements[0].indent = "";
1890     val = NULL;
1891        } else if (type == LT_MENUENTRY) {
1892     char *lineend = "--class gnu-linux --class gnu --class os {";
1893     if (!val) {
1894        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
1895        abort();
1896     }
1897     kw = getKeywordByType(type, cfi);
1898     if (!kw) {
1899        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1900        abort();
1901     }
1902     tmpl.indent = "";
1903     tmpl.type = type;
1904     tmpl.numElements = 3;
1905     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1906     tmpl.elements[0].item = kw->key;
1907     tmpl.elements[0].indent = alloca(2);
1908     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1909     tmpl.elements[1].item = (char *)val;
1910     tmpl.elements[1].indent = alloca(2);
1911     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
1912     tmpl.elements[2].item = alloca(strlen(lineend)+1);
1913     strcpy(tmpl.elements[2].item, lineend);
1914     tmpl.elements[2].indent = "";
1915        } else {
1916     kw = getKeywordByType(type, cfi);
1917     if (!kw) {
1918        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
1919        abort();
1920     }
1921     tmpl.type = type;
1922     tmpl.numElements = val ? 2 : 1;
1923     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
1924     tmpl.elements[0].item = kw->key;
1925     tmpl.elements[0].indent = alloca(2);
1926     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
1927     if (val) {
1928        tmpl.elements[1].item = (char *)val;
1929        tmpl.elements[1].indent = "";
1930     }
1931        }
1932    
1933      /* 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
1934         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
1935         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
1936         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
1937         differently from the rest) */         differently from the rest) */
1938      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
1939   line = entry->lines;   if (line->numElements) prev = line;
1940   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
1941   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;  
1942      }      }
1943    
1944      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
1945          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
1946          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
1947          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
1948          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
1949          line->elements[0].indent = malloc(2);   else
1950          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
1951          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
1952             if (menuEntry)
1953          if (val) {      tmpl.indent = "\t";
1954              line->elements[1].item = val;   else if (prev == entry->lines)
1955              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
1956          }   else
1957      } 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("");  
1958      }      }
1959    
1960      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
1961  }  }
1962    
1963  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 1982  void removeLine(struct singleEntry * ent
1982      free(line);      free(line);
1983  }  }
1984    
1985    static int isquote(char q)
1986    {
1987        if (q == '\'' || q == '\"')
1988     return 1;
1989        return 0;
1990    }
1991    
1992    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
1993    {
1994        struct singleLine newLine = {
1995     .indent = tmplLine->indent,
1996     .type = tmplLine->type,
1997     .next = tmplLine->next,
1998        };
1999        int firstQuotedItem = -1;
2000        int quoteLen = 0;
2001        int j;
2002        int element = 0;
2003        char *c;
2004    
2005        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2006        strcpy(c, tmplLine->elements[0].item);
2007        insertElement(&newLine, c, element++, cfi);
2008        free(c);
2009        c = NULL;
2010    
2011        for (j = 1; j < tmplLine->numElements; j++) {
2012     if (firstQuotedItem == -1) {
2013        quoteLen += strlen(tmplLine->elements[j].item);
2014        
2015        if (isquote(tmplLine->elements[j].item[0])) {
2016     firstQuotedItem = j;
2017            quoteLen += strlen(tmplLine->elements[j].indent);
2018        } else {
2019     c = malloc(quoteLen + 1);
2020     strcpy(c, tmplLine->elements[j].item);
2021     insertElement(&newLine, c, element++, cfi);
2022     free(c);
2023     quoteLen = 0;
2024        }
2025     } else {
2026        int itemlen = strlen(tmplLine->elements[j].item);
2027        quoteLen += itemlen;
2028        quoteLen += strlen(tmplLine->elements[j].indent);
2029        
2030        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2031     c = malloc(quoteLen + 1);
2032     c[0] = '\0';
2033     for (int i = firstQuotedItem; i < j+1; i++) {
2034        strcat(c, tmplLine->elements[i].item);
2035        strcat(c, tmplLine->elements[i].indent);
2036     }
2037     insertElement(&newLine, c, element++, cfi);
2038     free(c);
2039    
2040     firstQuotedItem = -1;
2041     quoteLen = 0;
2042        }
2043     }
2044        }
2045        while (tmplLine->numElements)
2046     removeElement(tmplLine, 0);
2047        if (tmplLine->elements)
2048     free(tmplLine->elements);
2049    
2050        tmplLine->numElements = newLine.numElements;
2051        tmplLine->elements = newLine.elements;
2052    }
2053    
2054    static void insertElement(struct singleLine * line,
2055      const char * item, int insertHere,
2056      struct configFileInfo * cfi)
2057    {
2058        struct keywordTypes * kw;
2059        char indent[2] = "";
2060    
2061        /* sanity check */
2062        if (insertHere > line->numElements) {
2063     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2064      insertHere, line->numElements);
2065     insertHere = line->numElements;
2066        }
2067    
2068        line->elements = realloc(line->elements, (line->numElements + 1) *
2069         sizeof(*line->elements));
2070        memmove(&line->elements[insertHere+1],
2071        &line->elements[insertHere],
2072        (line->numElements - insertHere) *
2073        sizeof(*line->elements));
2074        line->elements[insertHere].item = strdup(item);
2075    
2076        kw = getKeywordByType(line->type, cfi);
2077    
2078        if (line->numElements == 0) {
2079     indent[0] = '\0';
2080        } else if (insertHere == 0) {
2081     indent[0] = kw->nextChar;
2082        } else if (kw->separatorChar != '\0') {
2083     indent[0] = kw->separatorChar;
2084        } else {
2085     indent[0] = ' ';
2086        }
2087    
2088        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2089     /* move the end-of-line forward */
2090     line->elements[insertHere].indent =
2091        line->elements[insertHere-1].indent;
2092     line->elements[insertHere-1].indent = strdup(indent);
2093        } else {
2094     line->elements[insertHere].indent = strdup(indent);
2095        }
2096    
2097        line->numElements++;
2098    
2099        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2100          line->elements[0].item,
2101          line->elements[insertHere].item,
2102          line->elements[insertHere].indent,
2103          insertHere);
2104    }
2105    
2106    static void removeElement(struct singleLine * line, int removeHere) {
2107        int i;
2108    
2109        /* sanity check */
2110        if (removeHere >= line->numElements) return;
2111    
2112        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2113          removeHere, line->elements[removeHere].item);
2114    
2115        free(line->elements[removeHere].item);
2116    
2117        if (removeHere > 1) {
2118     /* previous argument gets this argument's post-indentation */
2119     free(line->elements[removeHere-1].indent);
2120     line->elements[removeHere-1].indent =
2121        line->elements[removeHere].indent;
2122        } else {
2123     free(line->elements[removeHere].indent);
2124        }
2125    
2126        /* now collapse the array, but don't bother to realloc smaller */
2127        for (i = removeHere; i < line->numElements - 1; i++)
2128     line->elements[i] = line->elements[i + 1];
2129    
2130        line->numElements--;
2131    }
2132    
2133  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2134      char * first, * second;      char * first, * second;
2135      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2152  int updateActualImage(struct grubConfig
2152      struct singleEntry * entry;      struct singleEntry * entry;
2153      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2154      int index = 0;      int index = 0;
2155      int i, j, k;      int i, k;
2156      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2157      const char ** arg;      const char ** arg;
2158      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2159      int firstElement;      int firstElement;
2160      int *usedElements, *usedArgs;      int *usedElements;
2161        int doreplace;
2162    
2163      if (!image) return 0;      if (!image) return 0;
2164    
# Line 1609  int updateActualImage(struct grubConfig Line 2185  int updateActualImage(struct grubConfig
2185   }   }
2186      }      }
2187    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2188    
2189      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2190   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2191    
2192      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2193   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2194    
2195      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2196    
2197      k = 0;   if (multibootArgs && !entry->multiboot)
2198      for (arg = newArgs; *arg; arg++)      continue;
2199          k++;  
2200      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2201     * LT_KERNELARGS, use that.  Otherwise use
2202     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2203     */
2204     if (useKernelArgs) {
2205        line = getLineByType(LT_KERNELARGS, entry->lines);
2206        if (!line) {
2207     /* no LT_KERNELARGS, need to add it */
2208     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2209           cfg->secondaryIndent, NULL);
2210        }
2211        firstElement = 1;
2212    
2213      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2214   index++;      line = getLineByType(LT_HYPER, entry->lines);
2215        if (!line) {
2216     /* a multiboot entry without LT_HYPER? */
2217     continue;
2218        }
2219        firstElement = 2;
2220    
2221   line = entry->lines;   } else {
2222   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2223   if (!line) continue;      if (!line) {
2224   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2225     continue;
2226          if (entry->multiboot && !multibootArgs) {      }
2227              /* 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;  
2228   }   }
2229    
2230   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2231      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2232      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2233     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2234        /* this is a multiboot entry, make sure there's
2235         * -- on the args line
2236         */
2237        for (i = firstElement; i < line->numElements; i++) {
2238     if (!strcmp(line->elements[i].item, "--"))
2239        break;
2240        }
2241        if (i == line->numElements) {
2242     /* assume all existing args are kernel args,
2243     * prepend -- to make it official
2244     */
2245     insertElement(line, "--", firstElement, cfg->cfi);
2246     i = firstElement;
2247        }
2248        if (!multibootArgs) {
2249     /* kernel args start after the -- */
2250     firstElement = i + 1;
2251        }
2252     } else if (cfg->cfi->mbConcatArgs) {
2253        /* this is a non-multiboot entry, remove hyper args */
2254        for (i = firstElement; i < line->numElements; i++) {
2255     if (!strcmp(line->elements[i].item, "--"))
2256        break;
2257        }
2258        if (i < line->numElements) {
2259     /* remove args up to -- */
2260     while (strcmp(line->elements[firstElement].item, "--"))
2261        removeElement(line, firstElement);
2262     /* remove -- */
2263     removeElement(line, firstElement);
2264        }
2265   }   }
2266    
2267          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2268    
2269          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2270   for (arg = newArgs; *arg; arg++) {  
2271              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2272      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2273     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2274        !strcmp(line->elements[i].item, "--"))
2275     {
2276        /* reached the end of hyper args, insert here */
2277        doreplace = 0;
2278        break;  
2279     }
2280                  if (usedElements[i])                  if (usedElements[i])
2281                      continue;                      continue;
2282   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2283                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2284      break;      break;
2285                  }                  }
2286              }              }
     chptr = strchr(*arg, '=');  
2287    
2288      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2289   /* replace */   /* direct replacement */
2290   free(line->elements[i].item);   free(line->elements[i].item);
2291   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("");  
  }  
2292    
2293   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2294   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2295      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2296   /* append */   if (rootLine) {
2297   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2298   (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(" ");  
2299   } else {   } else {
2300      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2301         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2302   }   }
2303        }
2304    
2305   line->numElements++;      else {
2306     /* insert/append */
2307     insertElement(line, *arg, i, cfg->cfi);
2308     usedElements = realloc(usedElements, line->numElements *
2309           sizeof(*usedElements));
2310     memmove(&usedElements[i + 1], &usedElements[i],
2311     line->numElements - i - 1);
2312     usedElements[i] = 1;
2313    
2314   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2315     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2316     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2317   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2318      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2319      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2320   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2321   }   }
2322      }      }
             k++;  
2323   }   }
2324    
2325          free(usedElements);          free(usedElements);
2326    
  /* 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? */  
2327   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2328      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2329   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2330        !strcmp(line->elements[i].item, "--"))
2331        /* reached the end of hyper args, stop here */
2332        break;
2333     if (!argMatch(line->elements[i].item, *arg)) {
2334        removeElement(line, i);
2335      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;  
2336   }   }
2337        }
2338   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2339        if (useRoot && !strncmp(*arg, "root=", 5)) {
2340   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2341      line->elements[j - 1] = line->elements[j];   if (rootLine)
2342        removeLine(entry, rootLine);
  line->numElements--;  
2343      }      }
2344   }   }
2345    
# Line 1760  int updateActualImage(struct grubConfig Line 2350  int updateActualImage(struct grubConfig
2350   }   }
2351      }      }
2352    
     free(usedArgs);  
2353      free(newArgs);      free(newArgs);
2354      free(oldArgs);      free(oldArgs);
2355    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2375  int updateImage(struct grubConfig * cfg,
2375      return rc;      return rc;
2376  }  }
2377    
2378    int updateInitrd(struct grubConfig * cfg, const char * image,
2379                     const char * prefix, const char * initrd) {
2380        struct singleEntry * entry;
2381        struct singleLine * line, * kernelLine, *endLine = NULL;
2382        int index = 0;
2383    
2384        if (!image) return 0;
2385    
2386        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2387            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2388            if (!kernelLine) continue;
2389    
2390            line = getLineByType(LT_INITRD, entry->lines);
2391            if (line)
2392                removeLine(entry, line);
2393            if (prefix) {
2394                int prefixLen = strlen(prefix);
2395                if (!strncmp(initrd, prefix, prefixLen))
2396                    initrd += prefixLen;
2397            }
2398     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2399     if (endLine)
2400        removeLine(entry, endLine);
2401            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2402            if (!line)
2403        return 1;
2404     if (endLine) {
2405        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2406                if (!line)
2407     return 1;
2408     }
2409    
2410            break;
2411        }
2412    
2413        return 0;
2414    }
2415    
2416  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2417      int fd;      int fd;
2418      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1956  int checkForLilo(struct grubConfig * con Line 2583  int checkForLilo(struct grubConfig * con
2583      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2584  }  }
2585    
2586    int checkForGrub2(struct grubConfig * config) {
2587        if (!access("/boot/grub2", R_OK))
2588     return 2;
2589    
2590        return 1;
2591    }
2592    
2593  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2594      int fd;      int fd;
2595      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2610  int checkForGrub(struct grubConfig * con
2610      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2611   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2612   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2613     close(fd);
2614     return 1;
2615        }
2616        close(fd);
2617    
2618        return checkDeviceBootloader(boot, bootSect);
2619    }
2620    
2621    int checkForExtLinux(struct grubConfig * config) {
2622        int fd;
2623        unsigned char bootSect[512];
2624        char * boot;
2625        char executable[] = "/boot/extlinux/extlinux";
2626    
2627        printf("entered: checkForExtLinux()\n");
2628    
2629        if (parseSysconfigGrub(NULL, &boot))
2630     return 0;
2631    
2632        /* assume grub is not installed -- not an error condition */
2633        if (!boot)
2634     return 0;
2635    
2636        fd = open(executable, O_RDONLY);
2637        if (fd < 0)
2638     /* this doesn't exist if grub hasn't been installed */
2639     return 0;
2640    
2641        if (read(fd, bootSect, 512) != 512) {
2642     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2643     executable, strerror(errno));
2644   return 1;   return 1;
2645      }      }
2646      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2659  static char * getRootSpecifier(char * st
2659      return rootspec;      return rootspec;
2660  }  }
2661    
2662    static char * getInitrdVal(struct grubConfig * config,
2663       const char * prefix, struct singleLine *tmplLine,
2664       const char * newKernelInitrd,
2665       char ** extraInitrds, int extraInitrdCount)
2666    {
2667        char *initrdVal, *end;
2668        int i;
2669        size_t totalSize;
2670        size_t prefixLen;
2671        char separatorChar;
2672    
2673        prefixLen = strlen(prefix);
2674        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2675    
2676        for (i = 0; i < extraInitrdCount; i++) {
2677     totalSize += sizeof(separatorChar);
2678     totalSize += strlen(extraInitrds[i]) - prefixLen;
2679        }
2680    
2681        initrdVal = end = malloc(totalSize);
2682    
2683        end = stpcpy (end, newKernelInitrd + prefixLen);
2684    
2685        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2686        for (i = 0; i < extraInitrdCount; i++) {
2687     const char *extraInitrd;
2688     int j;
2689    
2690     extraInitrd = extraInitrds[i] + prefixLen;
2691     /* Don't add entries that are already there */
2692     if (tmplLine != NULL) {
2693        for (j = 2; j < tmplLine->numElements; j++)
2694     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2695        break;
2696    
2697        if (j != tmplLine->numElements)
2698     continue;
2699     }
2700    
2701     *end++ = separatorChar;
2702     end = stpcpy(end, extraInitrd);
2703        }
2704    
2705        return initrdVal;
2706    }
2707    
2708  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
2709           const char * prefix,           const char * prefix,
2710   char * newKernelPath, char * newKernelTitle,   char * newKernelPath, char * newKernelTitle,
2711   char * newKernelArgs, char * newKernelInitrd,   char * newKernelArgs, char * newKernelInitrd,
2712     char ** extraInitrds, int extraInitrdCount,
2713                   char * newMBKernel, char * newMBKernelArgs) {                   char * newMBKernel, char * newMBKernelArgs) {
2714      struct singleEntry * new;      struct singleEntry * new;
2715      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
2716      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
2717      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
2718    
2719      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
2720    
# Line 2036  int addNewKernel(struct grubConfig * con Line 2744  int addNewKernel(struct grubConfig * con
2744      config->entries = new;      config->entries = new;
2745    
2746      /* copy/update from the template */      /* copy/update from the template */
2747      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
2748        if (newKernelInitrd)
2749     needs |= NEED_INITRD;
2750      if (newMBKernel) {      if (newMBKernel) {
2751          needs |= KERNEL_MB;          needs |= NEED_MB;
2752          new->multiboot = 1;          new->multiboot = 1;
2753      }      }
2754    
2755      if (template) {      if (template) {
2756   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
2757      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
2758      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
2759   indent = tmplLine->indent;   {
2760        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
2761    
2762      /* skip comments */      /* skip comments */
2763      chptr = tmplLine->indent;      chptr = tmplLine->indent;
2764      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
2765      if (*chptr == '#') continue;      if (*chptr == '#') continue;
2766    
2767      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
2768      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
2769     if (!template->multiboot && (needs & NEED_MB)) {
2770              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
2771                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
2772                  struct singleLine *l;       * hypervisor at the same time.
2773                  needs &= ~ KERNEL_MB;       */
2774        if (config->cfi->mbHyperFirst) {
2775                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
2776                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
2777                                    newMBKernel + strlen(prefix));    tmplLine->indent,
2778                      newMBKernel + strlen(prefix));
2779                  tmplLine = lastLine;   /* set up for adding the kernel line */
2780                  if (!new->lines) {   free(tmplLine->indent);
2781                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
2782                  } else {   needs &= ~NEED_MB;
2783                      newLine->next = l;      }
2784                      newLine = l;      if (needs & NEED_KERNEL) {
2785                  }   /* use addLineTmpl to preserve line elements,
2786                  continue;   * otherwise we could just call addLine.  Unfortunately
2787              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
2788                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
2789                  continue; /* don't need multiboot kernel here */   * change below.
2790              }   */
2791     struct keywordTypes * mbm_kw =
2792        getKeywordByType(LT_MBMODULE, config->cfi);
2793     if (mbm_kw) {
2794        tmplLine->type = LT_MBMODULE;
2795        free(tmplLine->elements[0].item);
2796        tmplLine->elements[0].item = strdup(mbm_kw->key);
2797     }
2798     newLine = addLineTmpl(new, tmplLine, newLine,
2799          newKernelPath + strlen(prefix), config->cfi);
2800     needs &= ~NEED_KERNEL;
2801        }
2802        if (needs & NEED_MB) { /* !mbHyperFirst */
2803     newLine = addLine(new, config->cfi, LT_HYPER,
2804      config->secondaryIndent,
2805      newMBKernel + strlen(prefix));
2806     needs &= ~NEED_MB;
2807        }
2808     } else if (needs & NEED_KERNEL) {
2809        newLine = addLineTmpl(new, tmplLine, newLine,
2810      newKernelPath + strlen(prefix), config->cfi);
2811        needs &= ~NEED_KERNEL;
2812     }
2813    
2814      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
2815   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
2816   new->lines = newLine;   if (needs & NEED_MB) {
2817      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
2818   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
2819   newLine = newLine->next;      needs &= ~NEED_MB;
2820      }   }
2821    
2822        } else if (tmplLine->type == LT_MBMODULE &&
2823           tmplLine->numElements >= 2) {
2824     if (new->multiboot) {
2825        if (needs & NEED_KERNEL) {
2826     newLine = addLineTmpl(new, tmplLine, newLine,
2827          newKernelPath +
2828          strlen(prefix), config->cfi);
2829     needs &= ~NEED_KERNEL;
2830        } else if (config->cfi->mbInitRdIsModule &&
2831           (needs & NEED_INITRD)) {
2832     char *initrdVal;
2833     initrdVal = getInitrdVal(config, prefix, tmplLine,
2834     newKernelInitrd, extraInitrds,
2835     extraInitrdCount);
2836     newLine = addLineTmpl(new, tmplLine, newLine,
2837          initrdVal, config->cfi);
2838     free(initrdVal);
2839     needs &= ~NEED_INITRD;
2840        }
2841     } else if (needs & NEED_KERNEL) {
2842        /* template is multi but new is not,
2843         * insert the kernel in the first module slot
2844         */
2845        tmplLine->type = LT_KERNEL;
2846        free(tmplLine->elements[0].item);
2847        tmplLine->elements[0].item =
2848     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
2849        newLine = addLineTmpl(new, tmplLine, newLine,
2850      newKernelPath + strlen(prefix), config->cfi);
2851        needs &= ~NEED_KERNEL;
2852     } else if (needs & NEED_INITRD) {
2853        char *initrdVal;
2854        /* template is multi but new is not,
2855         * insert the initrd in the second module slot
2856         */
2857        tmplLine->type = LT_INITRD;
2858        free(tmplLine->elements[0].item);
2859        tmplLine->elements[0].item =
2860     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
2861        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2862        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2863        free(initrdVal);
2864        needs &= ~NEED_INITRD;
2865     }
2866    
     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));  
                 }  
2867      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
2868      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
2869   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
2870   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
2871                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
2872                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
2873                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
2874                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
2875                  }       */
2876                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
2877                  if (rootspec != NULL) {   char *initrdVal;
2878                      newLine->elements[1].item = sdupprintf("%s%s",  
2879                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2880                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
2881                                                             strlen(prefix));    config->secondaryIndent,
2882                  } else {    initrdVal);
2883                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
2884                                                         strlen(prefix));   needs &= ~NEED_INITRD;
2885                  }      }
2886              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
2887                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
2888   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
2889                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
2890                      free(newLine->elements[0].item);      free(initrdVal);
2891                      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);  
2892   }   }
2893    
2894   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
2895   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
2896   newLine->numElements = 2;   requote(tmplLine, config->cfi);
2897     char *nkt = malloc(strlen(newKernelTitle)+3);
2898     strcpy(nkt, "'");
2899     strcat(nkt, newKernelTitle);
2900     strcat(nkt, "'");
2901     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
2902     free(nkt);
2903     needs &= ~NEED_TITLE;
2904      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
2905                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
2906                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
2907                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
2908                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
2909                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
2910                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
2911                                             newLine->numElements);     config->cfi->titleBracketed) {
2912        /* addLineTmpl doesn't handle titleBracketed */
2913                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
2914                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
2915                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
2916                  newLine->numElements = 1;   }
2917              }      } else if (tmplLine->type == LT_ECHO) {
2918        requote(tmplLine, config->cfi);
2919        if (tmplLine->numElements > 1 &&
2920        strstr(tmplLine->elements[1].item, "'Loading Linux ")) {
2921     char *prefix = "'Loading ";
2922     char *newTitle = malloc(strlen(prefix) +
2923     strlen(newKernelTitle) + 2);
2924    
2925     strcpy(newTitle, prefix);
2926     strcat(newTitle, newKernelTitle);
2927     strcat(newTitle, "'");
2928     newLine = addLine(new, config->cfi, LT_ECHO,
2929     tmplLine->indent, newTitle);
2930     free(newTitle);
2931        } else {
2932     /* pass through other lines from the template */
2933     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
2934     config->cfi);
2935        }
2936        } else {
2937     /* pass through other lines from the template */
2938     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
2939        }
2940   }   }
2941    
2942      } else {      } else {
2943   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
2944      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
2945     */
2946     switch (config->cfi->entryStart) {
2947        case LT_KERNEL:
2948     if (new->multiboot && config->cfi->mbHyperFirst) {
2949        /* fall through to LT_HYPER */
2950     } else {
2951        newLine = addLine(new, config->cfi, LT_KERNEL,
2952          config->primaryIndent,
2953          newKernelPath + strlen(prefix));
2954        needs &= ~NEED_KERNEL;
2955        break;
2956     }
2957    
2958        case LT_HYPER:
2959     newLine = addLine(new, config->cfi, LT_HYPER,
2960      config->primaryIndent,
2961      newMBKernel + strlen(prefix));
2962     needs &= ~NEED_MB;
2963   break;   break;
         }  
2964    
2965   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
2966      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
2967       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
2968       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
2969      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
2970       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
2971      default:        config->primaryIndent, nkt);
2972                  /* zipl strikes again */   free(nkt);
2973                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
2974                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
2975                      chptr = newKernelTitle;   break;
2976                      type = LT_TITLE;      }
2977                      break;      case LT_TITLE:
2978                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
2979                      abort();   char * templabel;
2980                  }   int x = 0, y = 0;
2981   }  
2982     templabel = strdup(newKernelTitle);
2983     while( templabel[x]){
2984     if( templabel[x] == ' ' ){
2985     y = x;
2986     while( templabel[y] ){
2987     templabel[y] = templabel[y+1];
2988     y++;
2989     }
2990     }
2991     x++;
2992     }
2993     newLine = addLine(new, config->cfi, LT_TITLE,
2994      config->primaryIndent, templabel);
2995     free(templabel);
2996     }else{
2997     newLine = addLine(new, config->cfi, LT_TITLE,
2998      config->primaryIndent, newKernelTitle);
2999     }
3000     needs &= ~NEED_TITLE;
3001     break;
3002    
3003   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3004   new->lines = newLine;   abort();
3005     }
3006      }      }
3007    
3008      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3009          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3010              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3011                                config->secondaryIndent,       */
3012                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3013          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3014              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3015                                config->secondaryIndent,    newKernelTitle);
3016                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3017          /* don't need to check for title as it's guaranteed to have been      }
3018           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3019           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3020          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3021              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3022                                config->secondaryIndent,   needs &= ~NEED_MB;
3023                                newKernelInitrd + strlen(prefix));      }
3024      } else {      if (needs & NEED_KERNEL) {
3025          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3026              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3027                                config->secondaryIndent,        config->cfi)) ?
3028                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3029          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3030              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3031                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3032                                newKernelTitle);      }
3033          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3034              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3035                                config->secondaryIndent,    config->secondaryIndent,
3036                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3037     needs &= ~NEED_MB;
3038        }
3039        if (needs & NEED_INITRD) {
3040     char *initrdVal;
3041     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3042     newLine = addLine(new, config->cfi,
3043      (new->multiboot && getKeywordByType(LT_MBMODULE,
3044          config->cfi)) ?
3045      LT_MBMODULE : LT_INITRD,
3046      config->secondaryIndent,
3047      initrdVal);
3048     free(initrdVal);
3049     needs &= ~NEED_INITRD;
3050        }
3051        if (needs & NEED_END) {
3052     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3053     config->secondaryIndent, NULL);
3054     needs &= ~NEED_END;
3055        }
3056    
3057        if (needs) {
3058     printf(_("grubby: needs=%d, aborting\n"), needs);
3059     abort();
3060      }      }
3061    
3062      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3065  int addNewKernel(struct grubConfig * con
3065      return 0;      return 0;
3066  }  }
3067    
3068    static void traceback(int signum)
3069    {
3070        void *array[40];
3071        size_t size;
3072    
3073        signal(SIGSEGV, SIG_DFL);
3074        memset(array, '\0', sizeof (array));
3075        size = backtrace(array, 40);
3076    
3077        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3078                (unsigned long)size);
3079        backtrace_symbols_fd(array, size, STDERR_FILENO);
3080        exit(1);
3081    }
3082    
3083  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3084      poptContext optCon;      poptContext optCon;
3085      char * grubConfig = NULL;      const char * grubConfig = NULL;
3086      char * outputFile = NULL;      char * outputFile = NULL;
3087      int arg = 0;      int arg = 0;
3088      int flags = 0;      int flags = 0;
3089      int badImageOkay = 0;      int badImageOkay = 0;
3090        int configureGrub2 = 0;
3091      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3092      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3093        int configureExtLinux = 0;
3094      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3095        int extraInitrdCount = 0;
3096      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3097      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3098      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3108  int main(int argc, const char ** argv) {
3108      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3109      char * removeArgs = NULL;      char * removeArgs = NULL;
3110      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3111        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3112      const char * chptr = NULL;      const char * chptr = NULL;
3113      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3114      struct grubConfig * config;      struct grubConfig * config;
# Line 2339  int main(int argc, const char ** argv) { Line 3149  int main(int argc, const char ** argv) {
3149      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3150   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3151      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3152     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3153        _("configure extlinux bootloader (from syslinux)") },
3154   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3155      _("configure grub bootloader") },      _("configure grub bootloader") },
3156     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3157        _("configure grub2 bootloader") },
3158   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3159      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3160      _("kernel-path") },      _("kernel-path") },
3161   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3162      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3163     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3164        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3165   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3166      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3167   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3198  int main(int argc, const char ** argv) {
3198   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3199      };      };
3200    
3201        useextlinuxmenu=0;
3202    
3203        signal(SIGSEGV, traceback);
3204    
3205      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3206      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3207    
# Line 2391  int main(int argc, const char ** argv) { Line 3211  int main(int argc, const char ** argv) {
3211      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3212      exit(0);      exit(0);
3213      break;      break;
3214      case 'i':
3215        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3216         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3217        } else {
3218     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3219     return 1;
3220        }
3221        break;
3222   }   }
3223      }      }
3224    
# Line 2406  int main(int argc, const char ** argv) { Line 3234  int main(int argc, const char ** argv) {
3234   return 1;   return 1;
3235      }      }
3236    
3237      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3238   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3239     configureExtLinux ) > 1) {
3240   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3241   return 1;   return 1;
3242      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3243   fprintf(stderr,   fprintf(stderr,
3244      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3245   return 1;   return 1;
3246        } else if (configureGrub2) {
3247     cfi = &grub2ConfigType;
3248      } else if (configureLilo) {      } else if (configureLilo) {
3249   cfi = &liloConfigType;   cfi = &liloConfigType;
3250      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3257  int main(int argc, const char ** argv) {
3257          cfi = &siloConfigType;          cfi = &siloConfigType;
3258      } else if (configureZipl) {      } else if (configureZipl) {
3259          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3260        } else if (configureExtLinux) {
3261     cfi = &extlinuxConfigType;
3262     useextlinuxmenu=1;
3263      }      }
3264    
3265      if (!cfi) {      if (!cfi) {
# Line 2440  int main(int argc, const char ** argv) { Line 3274  int main(int argc, const char ** argv) {
3274        #elif __s390x__        #elif __s390x__
3275          cfi = &ziplConfigtype;          cfi = &ziplConfigtype;
3276        #else        #else
3277   cfi = &grubConfigType;          if (grub2FindConfig(&grub2ConfigType))
3278        cfi = &grub2ConfigType;
3279     else
3280        cfi = &grubConfigType;
3281        #endif        #endif
3282      }      }
3283    
3284      if (!grubConfig)      if (!grubConfig) {
3285   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3286        grubConfig = cfi->findConfig(cfi);
3287     if (!grubConfig)
3288        grubConfig = cfi->defaultConfig;
3289        }
3290    
3291      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3292    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
# Line 2465  int main(int argc, const char ** argv) { Line 3306  int main(int argc, const char ** argv) {
3306      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3307   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3308   return 1;   return 1;
3309      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3310    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3311    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3312   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3313   return 1;   return 1;
3314      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3361  int main(int argc, const char ** argv) {
3361   bootPrefix = "";   bootPrefix = "";
3362      }      }
3363    
3364        if (!cfi->mbAllowExtraInitRds &&
3365     extraInitrdCount > 0) {
3366     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3367     return 1;
3368        }
3369    
3370      if (bootloaderProbe) {      if (bootloaderProbe) {
3371   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3372   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3373    
3374     const char *grub2config = grub2FindConfig(&grub2ConfigType);
3375     if (grub2config) {
3376        gconfig = readConfig(grub2config, &grub2ConfigType);
3377        if (!gconfig)
3378     gr2c = 1;
3379        else
3380     gr2c = checkForGrub2(gconfig);
3381     }
3382    
3383   if (!access(grubConfigType.defaultConfig, F_OK)) {   if (!access(grubConfigType.defaultConfig, F_OK)) {
3384      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);
3385      if (!gconfig)      if (!gconfig)
# Line 2540  int main(int argc, const char ** argv) { Line 3396  int main(int argc, const char ** argv) {
3396   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3397   }   }
3398    
3399   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3400        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3401        if (!lconfig)
3402     erc = 1;
3403        else
3404     erc = checkForExtLinux(lconfig);
3405     }
3406    
3407     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3408    
3409   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3410     if (gr2c == 2) printf("grub2\n");
3411   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3412     if (erc == 2) printf("extlinux\n");
3413    
3414   return 0;   return 0;
3415      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3427  int main(int argc, const char ** argv) {
3427   if (!entry) return 0;   if (!entry) return 0;
3428   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3429    
3430   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3431   if (!line) return 0;   if (!line) return 0;
3432    
3433          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2585  int main(int argc, const char ** argv) { Line 3450  int main(int argc, const char ** argv) {
3450      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3451      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3452                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3453        if (updateKernelPath && newKernelInitrd) {
3454                if (updateInitrd(config, updateKernelPath, bootPrefix,
3455                                 newKernelInitrd)) return 1;
3456        }
3457      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3458                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3459                         extraInitrds, extraInitrdCount,
3460                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3461            
3462    
# Line 2597  int main(int argc, const char ** argv) { Line 3467  int main(int argc, const char ** argv) {
3467      }      }
3468    
3469      if (!outputFile)      if (!outputFile)
3470   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3471    
3472      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3473  }  }

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