Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1846 by niro, Mon Jul 2 13:00:11 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    #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43  #include "mount_by_label.h"  #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49    int debug = 0; /* Currently just for template debugging */
50    
51  #define _(A) (A)  #define _(A) (A)
52    
53    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
54  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
55    
56    #define NOOP_OPCODE 0x90
57    #define JMP_SHORT_OPCODE 0xeb
58    
59  /* comments get lumped in with indention */  /* comments get lumped in with indention */
60  struct lineElement {  struct lineElement {
61      char * item;      char * item;
62      char * indent;      char * indent;
63  };  };
64    
65  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
66         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
67         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
68        LT_KERNEL       = 1 << 2,
69        LT_INITRD       = 1 << 3,
70        LT_HYPER        = 1 << 4,
71        LT_DEFAULT      = 1 << 5,
72        LT_MBMODULE     = 1 << 6,
73        LT_ROOT         = 1 << 7,
74        LT_FALLBACK     = 1 << 8,
75        LT_KERNELARGS   = 1 << 9,
76        LT_BOOT         = 1 << 10,
77        LT_BOOTROOT     = 1 << 11,
78        LT_LBA          = 1 << 12,
79        LT_OTHER        = 1 << 13,
80        LT_GENERIC      = 1 << 14,
81        LT_ECHO    = 1 << 16,
82        LT_MENUENTRY    = 1 << 17,
83        LT_ENTRY_END    = 1 << 18,
84        LT_SET_VARIABLE = 1 << 19,
85        LT_UNKNOWN      = 1 << 20,
86    };
87    
88  struct singleLine {  struct singleLine {
89      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 104  struct singleEntry {
104    
105  #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 */
106    
107  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
108  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
109  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
110  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
111  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
112    #define NEED_MB      (1 << 4)
113    #define NEED_END     (1 << 5)
114    
115  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
116  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
117    #define DEFAULT_SAVED_GRUB2 -3
118    
119  struct keywordTypes {  struct keywordTypes {
120      char * key;      char * key;
121      enum lineType_e type;      enum lineType_e type;
122      char nextChar;      char nextChar;
123  } ;      char separatorChar;
124    };
125    
126    struct configFileInfo;
127    
128    typedef const char *(*findConfigFunc)(struct configFileInfo *);
129    typedef const int (*writeLineFunc)(struct configFileInfo *,
130     struct singleLine *line);
131    
132  struct configFileInfo {  struct configFileInfo {
133      char * defaultConfig;      char * defaultConfig;
134        findConfigFunc findConfig;
135        writeLineFunc writeLine;
136      struct keywordTypes * keywords;      struct keywordTypes * keywords;
137      int defaultIsIndex;      int defaultIsIndex;
138        int defaultIsVariable;
139      int defaultSupportSaved;      int defaultSupportSaved;
140      enum lineType_e entrySeparator;      enum lineType_e entryStart;
141        enum lineType_e entryEnd;
142      int needsBootPrefix;      int needsBootPrefix;
143      int argsInQuotes;      int argsInQuotes;
144      int maxTitleLength;      int maxTitleLength;
145      int titleBracketed;      int titleBracketed;
146        int titlePosition;
147        int mbHyperFirst;
148        int mbInitRdIsModule;
149        int mbConcatArgs;
150        int mbAllowExtraInitRds;
151  };  };
152    
153  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 156  struct keywordTypes grubKeywords[] = {
156      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
157      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
158      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
159      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
160      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
161        { "kernel",     LT_HYPER,       ' ' },
162      { NULL,    0, 0 },      { NULL,    0, 0 },
163  };  };
164    
165    const char *grubFindConfig(struct configFileInfo *cfi) {
166        static const char *configFiles[] = {
167     "/etc/grub.conf",
168     "/boot/grub/grub.conf",
169     "/boot/grub/menu.lst",
170     NULL
171        };
172        static int i = -1;
173    
174        if (i == -1) {
175     for (i = 0; configFiles[i] != NULL; i++) {
176        dbgPrintf("Checking \"%s\": ", configFiles[i]);
177        if (!access(configFiles[i], R_OK)) {
178     dbgPrintf("found\n");
179     return configFiles[i];
180        }
181        dbgPrintf("not found\n");
182     }
183        }
184        return configFiles[i];
185    }
186    
187  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
188      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
189      grubKeywords,    /* keywords */      .keywords = grubKeywords,
190      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
191      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
192      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
193      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
194      0,    /* argsInQuotes */      .mbHyperFirst = 1,
195      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
196      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
197    };
198    
199    struct keywordTypes grub2Keywords[] = {
200        { "menuentry",  LT_MENUENTRY,   ' ' },
201        { "}",          LT_ENTRY_END,   ' ' },
202        { "echo",       LT_ECHO,        ' ' },
203        { "set",        LT_SET_VARIABLE,' ', '=' },
204        { "root",       LT_BOOTROOT,    ' ' },
205        { "default",    LT_DEFAULT,     ' ' },
206        { "fallback",   LT_FALLBACK,    ' ' },
207        { "linux",      LT_KERNEL,      ' ' },
208        { "initrd",     LT_INITRD,      ' ', ' ' },
209        { "module",     LT_MBMODULE,    ' ' },
210        { "kernel",     LT_HYPER,       ' ' },
211        { NULL, 0, 0 },
212    };
213    
214    const char *grub2FindConfig(struct configFileInfo *cfi) {
215        static const char *configFiles[] = {
216     "/boot/grub/grub-efi.cfg",
217     "/boot/grub/grub.cfg",
218     NULL
219        };
220        static int i = -1;
221        static const char *grub_cfg = "/boot/grub/grub.cfg";
222    
223        if (i == -1) {
224     for (i = 0; configFiles[i] != NULL; i++) {
225        dbgPrintf("Checking \"%s\": ", configFiles[i]);
226        if (!access(configFiles[i], R_OK)) {
227     dbgPrintf("found\n");
228     return configFiles[i];
229        }
230     }
231        }
232    
233        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
234         * that isn't in grub1, and if it exists, return the config file path
235         * that they use. */
236        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
237     dbgPrintf("found\n");
238     return grub_cfg;
239        }
240    
241        dbgPrintf("not found\n");
242        return configFiles[i];
243    }
244    
245    int sizeOfSingleLine(struct singleLine * line) {
246      int count = 0;
247    
248      for (int i = 0; i < line->numElements; i++) {
249        int indentSize = 0;
250    
251        count = count + strlen(line->elements[i].item);
252    
253        indentSize = strlen(line->elements[i].indent);
254        if (indentSize > 0)
255          count = count + indentSize;
256        else
257          /* be extra safe and add room for whitespaces */
258          count = count + 1;
259      }
260    
261      /* room for trailing terminator */
262      count = count + 1;
263    
264      return count;
265    }
266    
267    static int isquote(char q)
268    {
269        if (q == '\'' || q == '\"')
270     return 1;
271        return 0;
272    }
273    
274    char *grub2ExtractTitle(struct singleLine * line) {
275        char * current;
276        char * current_indent;
277        int current_len;
278        int current_indent_len;
279        int i;
280    
281        /* bail out if line does not start with menuentry */
282        if (strcmp(line->elements[0].item, "menuentry"))
283          return NULL;
284    
285        i = 1;
286        current = line->elements[i].item;
287        current_len = strlen(current);
288    
289        /* if second word is quoted, strip the quotes and return single word */
290        if (isquote(*current) && isquote(current[current_len - 1])) {
291     char *tmp;
292    
293     tmp = strdup(current);
294     *(tmp + current_len - 1) = '\0';
295     return ++tmp;
296        }
297    
298        /* if no quotes, return second word verbatim */
299        if (!isquote(*current))
300     return current;
301    
302        /* second element start with a quote, so we have to find the element
303         * whose last character is also quote (assuming it's the closing one) */
304        int resultMaxSize;
305        char * result;
306        
307        resultMaxSize = sizeOfSingleLine(line);
308        result = malloc(resultMaxSize);
309        snprintf(result, resultMaxSize, "%s", ++current);
310        
311        i++;
312        for (; i < line->numElements; ++i) {
313     current = line->elements[i].item;
314     current_len = strlen(current);
315     current_indent = line->elements[i].indent;
316     current_indent_len = strlen(current_indent);
317    
318     strncat(result, current_indent, current_indent_len);
319     if (!isquote(current[current_len-1])) {
320        strncat(result, current, current_len);
321     } else {
322        strncat(result, current, current_len - 1);
323        break;
324     }
325        }
326        return result;
327    }
328    
329    struct configFileInfo grub2ConfigType = {
330        .findConfig = grub2FindConfig,
331        .keywords = grub2Keywords,
332        .defaultIsIndex = 1,
333        .defaultSupportSaved = 1,
334        .defaultIsVariable = 1,
335        .entryStart = LT_MENUENTRY,
336        .entryEnd = LT_ENTRY_END,
337        .titlePosition = 1,
338        .needsBootPrefix = 1,
339        .mbHyperFirst = 1,
340        .mbInitRdIsModule = 1,
341        .mbAllowExtraInitRds = 1,
342  };  };
343    
344  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 372  struct keywordTypes yabootKeywords[] = {
372      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
373      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
374      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
375      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
376      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
377      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
378      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 392  struct keywordTypes liloKeywords[] = {
392      { NULL,    0, 0 },      { NULL,    0, 0 },
393  };  };
394    
395    struct keywordTypes eliloKeywords[] = {
396        { "label",    LT_TITLE,    '=' },
397        { "root",    LT_ROOT,    '=' },
398        { "default",    LT_DEFAULT,    '=' },
399        { "image",    LT_KERNEL,    '=' },
400        { "initrd",    LT_INITRD,    '=' },
401        { "append",    LT_KERNELARGS,  '=' },
402        { "vmm",    LT_HYPER,       '=' },
403        { NULL,    0, 0 },
404    };
405    
406  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
407      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
408      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 424  struct keywordTypes ziplKeywords[] = {
424      { NULL,         0, 0 },      { NULL,         0, 0 },
425  };  };
426    
427    struct keywordTypes extlinuxKeywords[] = {
428        { "label",    LT_TITLE,    ' ' },
429        { "root",    LT_ROOT,    ' ' },
430        { "default",    LT_DEFAULT,    ' ' },
431        { "kernel",    LT_KERNEL,    ' ' },
432        { "initrd",    LT_INITRD,      ' ', ',' },
433        { "append",    LT_KERNELARGS,  ' ' },
434        { "prompt",     LT_UNKNOWN,     ' ' },
435        { NULL,    0, 0 },
436    };
437    int useextlinuxmenu;
438  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
439      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
440      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
441      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
442      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
443      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
444      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
445  };  };
446    
447  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
448      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
449      liloKeywords,    /* keywords */      .keywords = liloKeywords,
450      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
451      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
452      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
453  };  };
454    
455  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
456      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
457      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
458      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
459      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
460      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
461      1,    /* needsBootPrefix */      .maxTitleLength = 15,
462      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
463  };  };
464    
465  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
466      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
467      siloKeywords,    /* keywords */      .keywords = siloKeywords,
468      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
469      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
470      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
471      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
472  };  };
473    
474  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
475      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
476      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
477      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
478      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
479      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
480      0,    /* needsBootPrefix */  };
481      1,    /* argsInQuotes */  
482      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
483      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
484        .keywords = extlinuxKeywords,
485        .entryStart = LT_TITLE,
486        .needsBootPrefix = 1,
487        .maxTitleLength = 255,
488        .mbAllowExtraInitRds = 1,
489  };  };
490    
491  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 500  struct grubConfig {
500      struct configFileInfo * cfi;      struct configFileInfo * cfi;
501  };  };
502    
503    blkid_cache blkid;
504    
505  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
506  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
507       const char * path, const char * prefix,       const char * path, const char * prefix,
508       int * index);       int * index);
 static char * strndup(char * from, int len);  
509  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
510  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
511    struct singleLine * lineDup(struct singleLine * line);
512  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
513  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
514       struct configFileInfo * cfi);       struct configFileInfo * cfi);
515  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
516         struct configFileInfo * cfi);         struct configFileInfo * cfi);
517  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
518    static void requote(struct singleLine *line, struct configFileInfo * cfi);
519  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
520      char * to;    const char * item, int insertHere,
521      struct configFileInfo * cfi);
522      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
523      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
524      to[len] = '\0';        struct configFileInfo * cfi);
525    static enum lineType_e getTypeByKeyword(char * keyword,
526      return to;   struct configFileInfo * cfi);
527  }  static struct singleLine * getLineByType(enum lineType_e type,
528     struct singleLine * line);
529    static int checkForExtLinux(struct grubConfig * config);
530    struct singleLine * addLineTmpl(struct singleEntry * entry,
531                                    struct singleLine * tmplLine,
532                                    struct singleLine * prevLine,
533                                    const char * val,
534     struct configFileInfo * cfi);
535    struct singleLine *  addLine(struct singleEntry * entry,
536                                 struct configFileInfo * cfi,
537                                 enum lineType_e type, char * defaultIndent,
538                                 const char * val);
539    
540  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
541  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 570  static char * sdupprintf(const char *for
570      return buf;      return buf;
571  }  }
572    
573    static struct keywordTypes * getKeywordByType(enum lineType_e type,
574          struct configFileInfo * cfi) {
575        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
576     if (kw->type == type)
577        return kw;
578        }
579        return NULL;
580    }
581    
582    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
583        struct keywordTypes *kt = getKeywordByType(type, cfi);
584        if (kt)
585     return kt->key;
586        return "unknown";
587    }
588    
589    static char * getpathbyspec(char *device) {
590        if (!blkid)
591            blkid_get_cache(&blkid, NULL);
592    
593        return blkid_get_devname(blkid, device, NULL);
594    }
595    
596    static char * getuuidbydev(char *device) {
597        if (!blkid)
598     blkid_get_cache(&blkid, NULL);
599    
600        return blkid_get_tag_value(blkid, "UUID", device);
601    }
602    
603    static enum lineType_e getTypeByKeyword(char * keyword,
604     struct configFileInfo * cfi) {
605        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
606     if (!strcmp(keyword, kw->key))
607        return kw->type;
608        }
609        return LT_UNKNOWN;
610    }
611    
612    static struct singleLine * getLineByType(enum lineType_e type,
613     struct singleLine * line) {
614        dbgPrintf("getLineByType(%d): ", type);
615        for (; line; line = line->next) {
616     dbgPrintf("%d:%s ", line->type,
617      line->numElements ? line->elements[0].item : "(empty)");
618     if (line->type & type) break;
619        }
620        dbgPrintf(line ? "\n" : " (failed)\n");
621        return line;
622    }
623    
624  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
625      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
626          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
627          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
628              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 634  static int isBracketedTitle(struct singl
634      return 0;      return 0;
635  }  }
636    
637  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
638                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
639      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
640   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;  
641  }  }
642    
643  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 688  static void lineInit(struct singleLine *
688      line->next = NULL;      line->next = NULL;
689  }  }
690    
691  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
692      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
693    
694        newLine->indent = strdup(line->indent);
695        newLine->next = NULL;
696        newLine->type = line->type;
697        newLine->numElements = line->numElements;
698        newLine->elements = malloc(sizeof(*newLine->elements) *
699           newLine->numElements);
700    
701        for (int i = 0; i < newLine->numElements; i++) {
702     newLine->elements[i].indent = strdup(line->elements[i].indent);
703     newLine->elements[i].item = strdup(line->elements[i].item);
704        }
705    
706        return newLine;
707    }
708    
709    static void lineFree(struct singleLine * line) {
710      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
711    
712      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
713   free(line->elements[i].item);   free(line->elements[i].item);
714   free(line->elements[i].indent);   free(line->elements[i].indent);
715      }      }
# Line 405  static void lineFree(struct singleLine * Line 720  static void lineFree(struct singleLine *
720    
721  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
722       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
723      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
724    
725      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
726     /* Need to handle this, because we strip the quotes from
727     * menuentry when read it. */
728     if (line->type == LT_MENUENTRY && i == 1) {
729        if(!isquote(*line->elements[i].item))
730     fprintf(out, "\'%s\'", line->elements[i].item);
731        else
732     fprintf(out, "%s", line->elements[i].item);
733        fprintf(out, "%s", line->elements[i].indent);
734    
735        continue;
736     }
737    
738   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
739      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
740    
741   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
742   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
743        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
744      }      }
745    
746      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 759  static int getNextLine(char ** bufPtr, s
759      char * chptr;      char * chptr;
760      int elementsAlloced = 0;      int elementsAlloced = 0;
761      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
762      int first = 1;      int first = 1;
     int i;  
763    
764      lineFree(line);      lineFree(line);
765    
# Line 489  static int getNextLine(char ** bufPtr, s Line 813  static int getNextLine(char ** bufPtr, s
813      if (!line->numElements)      if (!line->numElements)
814   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
815      else {      else {
816   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
817      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;  
               
818              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
819               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
820              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 828  static int getNextLine(char ** bufPtr, s
828      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
829   char * fullLine;   char * fullLine;
830   int len;   int len;
  int i;  
831    
832   len = strlen(line->indent);   len = strlen(line->indent);
833   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
834      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
835     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
836    
# Line 522  static int getNextLine(char ** bufPtr, s Line 839  static int getNextLine(char ** bufPtr, s
839   free(line->indent);   free(line->indent);
840   line->indent = fullLine;   line->indent = fullLine;
841    
842   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
843      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
844      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
845      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 849  static int getNextLine(char ** bufPtr, s
849   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
850   line->numElements = 0;   line->numElements = 0;
851      }      }
852     } else {
853     struct keywordTypes *kw;
854    
855     kw = getKeywordByType(line->type, cfi);
856    
857     /* space isn't the only separator, we need to split
858     * elements up more
859     */
860     if (!isspace(kw->separatorChar)) {
861        char indent[2] = "";
862        indent[0] = kw->separatorChar;
863        for (int i = 1; i < line->numElements; i++) {
864     char *p;
865     int numNewElements;
866    
867     numNewElements = 0;
868     p = line->elements[i].item;
869     while (*p != '\0') {
870     if (*p == kw->separatorChar)
871     numNewElements++;
872     p++;
873     }
874     if (line->numElements + numNewElements >= elementsAlloced) {
875     elementsAlloced += numNewElements + 5;
876     line->elements = realloc(line->elements,
877        sizeof(*line->elements) * elementsAlloced);
878     }
879    
880     for (int j = line->numElements; j > i; j--) {
881     line->elements[j + numNewElements] = line->elements[j];
882     }
883     line->numElements += numNewElements;
884    
885     p = line->elements[i].item;
886     while (*p != '\0') {
887    
888     while (*p != kw->separatorChar && *p != '\0') p++;
889     if (*p == '\0') {
890     break;
891     }
892    
893     line->elements[i + 1].indent = line->elements[i].indent;
894     line->elements[i].indent = strdup(indent);
895     *p++ = '\0';
896     i++;
897     line->elements[i].item = strdup(p);
898     }
899        }
900     }
901   }   }
902      }      }
903    
# Line 549  static struct grubConfig * readConfig(co Line 915  static struct grubConfig * readConfig(co
915      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
916      char * end;      char * end;
917      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
918      int i, len;      int len;
919      char * buf;      char * buf;
920    
921      if (!strcmp(inName, "-")) {      if (!strcmp(inName, "-")) {
# Line 595  static struct grubConfig * readConfig(co Line 961  static struct grubConfig * readConfig(co
961      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
962   }   }
963    
964   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
965      sawEntry = 1;      sawEntry = 1;
966      if (!entry) {      if (!entry) {
967   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 977  static struct grubConfig * readConfig(co
977      entry->next = NULL;      entry->next = NULL;
978   }   }
979    
980   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
981        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
982        dbgPrintf("%s", line->indent);
983        for (int i = 0; i < line->numElements; i++)
984     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
985        dbgPrintf("\n");
986        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
987        if (kwType && line->numElements == 3 &&
988        !strcmp(line->elements[1].item, kwType->key)) {
989     dbgPrintf("Line sets default config\n");
990     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
991     defaultLine = line;
992        }
993     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
994      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
995      defaultLine = line;      defaultLine = line;
996    
997            } else if (line->type == LT_KERNEL) {
998        /* if by some freak chance this is multiboot and the "module"
999         * lines came earlier in the template, make sure to use LT_HYPER
1000         * instead of LT_KERNEL now
1001         */
1002        if (entry->multiboot)
1003     line->type = LT_HYPER;
1004    
1005          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1006        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1007         * instead, now that we know this is a multiboot entry.
1008         * This only applies to grub, but that's the only place we
1009         * should find LT_MBMODULE lines anyway.
1010         */
1011        for (struct singleLine *l = entry->lines; l; l = l->next) {
1012     if (l->type == LT_HYPER)
1013        break;
1014     else if (l->type == LT_KERNEL) {
1015        l->type = LT_HYPER;
1016        break;
1017     }
1018        }
1019              entry->multiboot = 1;              entry->multiboot = 1;
1020    
1021     } else if (line->type == LT_HYPER) {
1022        entry->multiboot = 1;
1023    
1024   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1025      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1026      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1027    
1028   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1029      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1030      len = 0;      len = 0;
1031      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1032   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1033   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1034      }      }
1035      buf = malloc(len + 1);      buf = malloc(len + 1);
1036      *buf = '\0';      *buf = '\0';
1037    
1038      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1039   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1040   free(line->elements[i].item);   free(line->elements[i].item);
1041    
# Line 643  static struct grubConfig * readConfig(co Line 1049  static struct grubConfig * readConfig(co
1049      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1050      line->elements[1].item = buf;      line->elements[1].item = buf;
1051      line->numElements = 2;      line->numElements = 2;
1052     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1053        /* let --remove-kernel="TITLE=what" work */
1054        len = 0;
1055        char *extras;
1056        char *title;
1057    
1058        for (int i = 1; i < line->numElements; i++) {
1059     len += strlen(line->elements[i].item);
1060     len += strlen(line->elements[i].indent);
1061        }
1062        buf = malloc(len + 1);
1063        *buf = '\0';
1064    
1065        /* allocate mem for extra flags. */
1066        extras = malloc(len + 1);
1067        *extras = '\0';
1068    
1069        /* get title. */
1070        for (int i = 0; i < line->numElements; i++) {
1071     if (!strcmp(line->elements[i].item, "menuentry"))
1072        continue;
1073     if (isquote(*line->elements[i].item))
1074        title = line->elements[i].item + 1;
1075     else
1076        title = line->elements[i].item;
1077    
1078     len = strlen(title);
1079            if (isquote(title[len-1])) {
1080        strncat(buf, title,len-1);
1081        break;
1082     } else {
1083        strcat(buf, title);
1084        strcat(buf, line->elements[i].indent);
1085     }
1086        }
1087    
1088        /* get extras */
1089        int count = 0;
1090        for (int i = 0; i < line->numElements; i++) {
1091     if (count >= 2) {
1092        strcat(extras, line->elements[i].item);
1093        strcat(extras, line->elements[i].indent);
1094     }
1095    
1096     if (!strcmp(line->elements[i].item, "menuentry"))
1097        continue;
1098    
1099     /* count ' or ", there should be two in menuentry line. */
1100     if (isquote(*line->elements[i].item))
1101        count++;
1102    
1103     len = strlen(line->elements[i].item);
1104    
1105     if (isquote(line->elements[i].item[len -1]))
1106        count++;
1107    
1108     /* ok, we get the final ' or ", others are extras. */
1109                }
1110        line->elements[1].indent =
1111     line->elements[line->numElements - 2].indent;
1112        line->elements[1].item = buf;
1113        line->elements[2].indent =
1114     line->elements[line->numElements - 2].indent;
1115        line->elements[2].item = extras;
1116        line->numElements = 3;
1117   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1118      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1119         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 651  static struct grubConfig * readConfig(co Line 1122  static struct grubConfig * readConfig(co
1122      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1123   int last, len;   int last, len;
1124    
1125   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1126      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1127     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1128    
1129   last = line->numElements - 1;   last = line->numElements - 1;
1130   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1131   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1132      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1133      }      }
   
1134   }   }
1135    
1136   /* 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 1150  static struct grubConfig * readConfig(co
1150   movedLine = 1;   movedLine = 1;
1151   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1152   }   }
1153    
1154   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1155     which was moved, drop it. */     which was moved, drop it. */
1156   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 1166  static struct grubConfig * readConfig(co
1166   entry->lines = line;   entry->lines = line;
1167      else      else
1168   last->next = line;   last->next = line;
1169        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1170    
1171        /* we could have seen this outside of an entry... if so, we
1172         * ignore it like any other line we don't grok */
1173        if (line->type == LT_ENTRY_END && sawEntry)
1174     sawEntry = 0;
1175   } else {   } else {
1176      if (!cfg->theLines)      if (!cfg->theLines)
1177   cfg->theLines = line;   cfg->theLines = line;
1178      else {      else
1179   last->next = line;   last->next = line;
1180      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1181   }   }
1182    
1183   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1185  static struct grubConfig * readConfig(co
1185    
1186      free(incoming);      free(incoming);
1187    
1188        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1189      if (defaultLine) {      if (defaultLine) {
1190   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1191        cfi->defaultSupportSaved &&
1192        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1193        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1194     } else if (cfi->defaultIsVariable) {
1195        char *value = defaultLine->elements[2].item;
1196        while (*value && (*value == '"' || *value == '\'' ||
1197        *value == ' ' || *value == '\t'))
1198     value++;
1199        cfg->defaultImage = strtol(value, &end, 10);
1200        while (*end && (*end == '"' || *end == '\'' ||
1201        *end == ' ' || *end == '\t'))
1202     end++;
1203        if (*end) cfg->defaultImage = -1;
1204     } else if (cfi->defaultSupportSaved &&
1205   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1206      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1207   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1208      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1209      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1210   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1211      i = 0;      int i = 0;
1212      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1213   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1214      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1222  static struct grubConfig * readConfig(co
1222                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1223                  }                  }
1224   i++;   i++;
1225     entry = NULL;
1226      }      }
1227    
1228      if (entry) cfg->defaultImage = i;      if (entry){
1229            cfg->defaultImage = i;
1230        }else{
1231            cfg->defaultImage = -1;
1232        }
1233   }   }
1234        } else {
1235            cfg->defaultImage = 0;
1236      }      }
1237    
1238      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1248  static void writeDefault(FILE * out, cha
1248    
1249      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1250   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1251        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1252     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1253      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1254   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1255      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1256      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1257     cfg->defaultImage);
1258        } else {
1259     fprintf(out, "%sdefault%s%d\n", indent, separator,
1260     cfg->defaultImage);
1261        }
1262   } else {   } else {
1263      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1264    
# Line 769  static void writeDefault(FILE * out, cha Line 1275  static void writeDefault(FILE * out, cha
1275    
1276      if (!entry) return;      if (!entry) return;
1277    
1278      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1279    
1280      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1281   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1309  static int writeConfig(struct grubConfig
1309      int rc;      int rc;
1310    
1311      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1312         directory to / */         directory to the dir of the symlink */
1313      rc = chdir("/");              rc = chdir(dirname(outName));
1314      do {      do {
1315   buf = alloca(len + 1);   buf = alloca(len + 1);
1316   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1317   if (rc == len) len += 256;   if (rc == len) len += 256;
1318      } while (rc == len);      } while (rc == len);
1319            
# Line 843  static int writeConfig(struct grubConfig Line 1348  static int writeConfig(struct grubConfig
1348      }      }
1349    
1350      line = cfg->theLines;      line = cfg->theLines;
1351        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1352      while (line) {      while (line) {
1353   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1354     line->numElements == 3 &&
1355     !strcmp(line->elements[1].item, defaultKw->key)) {
1356        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1357        needs &= ~MAIN_DEFAULT;
1358     } else if (line->type == LT_DEFAULT) {
1359      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1360      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1361   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1423  static int numEntries(struct grubConfig
1423      return i;      return i;
1424  }  }
1425    
1426    static char *findDiskForRoot()
1427    {
1428        int fd;
1429        char buf[65536];
1430        char *devname;
1431        char *chptr;
1432        int rc;
1433    
1434        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1435            fprintf(stderr, "grubby: failed to open %s: %s\n",
1436                    _PATH_MOUNTED, strerror(errno));
1437            return NULL;
1438        }
1439    
1440        rc = read(fd, buf, sizeof(buf) - 1);
1441        if (rc <= 0) {
1442            fprintf(stderr, "grubby: failed to read %s: %s\n",
1443                    _PATH_MOUNTED, strerror(errno));
1444            close(fd);
1445            return NULL;
1446        }
1447        close(fd);
1448        buf[rc] = '\0';
1449        chptr = buf;
1450    
1451        char *foundanswer = NULL;
1452    
1453        while (chptr && chptr != buf+rc) {
1454            devname = chptr;
1455    
1456            /*
1457             * The first column of a mtab entry is the device, but if the entry is a
1458             * special device it won't start with /, so move on to the next line.
1459             */
1460            if (*devname != '/') {
1461                chptr = strchr(chptr, '\n');
1462                if (chptr)
1463                    chptr++;
1464                continue;
1465            }
1466    
1467            /* Seek to the next space */
1468            chptr = strchr(chptr, ' ');
1469            if (!chptr) {
1470                fprintf(stderr, "grubby: error parsing %s: %s\n",
1471                        _PATH_MOUNTED, strerror(errno));
1472                return NULL;
1473            }
1474    
1475            /*
1476             * The second column of a mtab entry is the mount point, we are looking
1477             * for '/' obviously.
1478             */
1479            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1480                /* remember the last / entry in mtab */
1481               foundanswer = devname;
1482            }
1483    
1484            /* Next line */
1485            chptr = strchr(chptr, '\n');
1486            if (chptr)
1487                chptr++;
1488        }
1489    
1490        /* Return the last / entry found */
1491        if (foundanswer) {
1492            chptr = strchr(foundanswer, ' ');
1493            *chptr = '\0';
1494            return strdup(foundanswer);
1495        }
1496    
1497        return NULL;
1498    }
1499    
1500    void printEntry(struct singleEntry * entry) {
1501        int i;
1502        struct singleLine * line;
1503    
1504        for (line = entry->lines; line; line = line->next) {
1505     fprintf(stderr, "DBG: %s", line->indent);
1506     for (i = 0; i < line->numElements; i++) {
1507        /* Need to handle this, because we strip the quotes from
1508         * menuentry when read it. */
1509        if (line->type == LT_MENUENTRY && i == 1) {
1510     if(!isquote(*line->elements[i].item))
1511        fprintf(stderr, "\'%s\'", line->elements[i].item);
1512     else
1513        fprintf(stderr, "%s", line->elements[i].item);
1514     fprintf(stderr, "%s", line->elements[i].indent);
1515    
1516     continue;
1517        }
1518        
1519        fprintf(stderr, "%s%s",
1520        line->elements[i].item, line->elements[i].indent);
1521     }
1522     fprintf(stderr, "\n");
1523        }
1524    }
1525    
1526    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1527    {
1528        va_list argp;
1529    
1530        if (!debug)
1531     return;
1532    
1533        va_start(argp, fmt);
1534        fprintf(stderr, "DBG: Image entry failed: ");
1535        vfprintf(stderr, fmt, argp);
1536        printEntry(entry);
1537        va_end(argp);
1538    }
1539    
1540    #define beginswith(s, c) ((s) && (s)[0] == (c))
1541    
1542    static int endswith(const char *s, char c)
1543    {
1544     int slen;
1545    
1546     if (!s || !s[0])
1547     return 0;
1548     slen = strlen(s) - 1;
1549    
1550     return s[slen] == c;
1551    }
1552    
1553  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1554    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1555      struct singleLine * line;      struct singleLine * line;
1556      char * fullName;      char * fullName;
1557      int i;      int i;
     struct stat sb, sb2;  
1558      char * dev;      char * dev;
     char * end;  
1559      char * rootspec;      char * rootspec;
1560        char * rootdev;
1561    
1562      line = entry->lines;      if (skipRemoved && entry->skip) {
1563      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1564         return 0;
1565      if (!line) return 0;      }
1566      if (skipRemoved && entry->skip) return 0;  
1567      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1568        if (!line) {
1569     notSuitablePrintf(entry, "no line found\n");
1570     return 0;
1571        }
1572        if (line->numElements < 2) {
1573     notSuitablePrintf(entry, "line has only %d elements\n",
1574        line->numElements);
1575     return 0;
1576        }
1577    
1578      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1579    
1580      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1581        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1582      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1583      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1584              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1585                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1586      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1587                line->elements[1].item + rootspec_offset);
1588        if (access(fullName, R_OK)) {
1589     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1590     return 0;
1591        }
1592      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1593   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1594      if (i < line->numElements) {      if (i < line->numElements) {
1595   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1596      } else {      } else {
1597   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1598   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1599    
1600   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1601      dev = line->elements[1].item;      dev = line->elements[1].item;
1602   } else {   } else {
1603              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1604      /* 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.
1605      line = entry->lines;       */
1606        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1607    
1608              /* failed to find one */              /* failed to find one */
1609              if (!line) return 0;              if (!line) {
1610     notSuitablePrintf(entry, "no line found\n");
1611     return 0;
1612                }
1613    
1614      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1615          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1616      if (i < line->numElements)      if (i < line->numElements)
1617          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1618      else {      else {
1619     notSuitablePrintf(entry, "no root= entry found\n");
1620   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1621          return 0;          return 0;
1622              }              }
1623   }   }
1624      }      }
1625    
1626      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1627   dev += 6;      if (!getpathbyspec(dev)) {
1628            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1629   /* check which device has this label */          return 0;
1630   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1631   if (!dev) return 0;   dev = getpathbyspec(dev);
1632    
1633        rootdev = findDiskForRoot();
1634        if (!rootdev) {
1635            notSuitablePrintf(entry, "can't find root device\n");
1636     return 0;
1637      }      }
1638    
1639      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1640   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1641      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1642      } else {          free(rootdev);
1643   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1644   if (*end) return 0;      }
1645    
1646        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1647            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1648     getuuidbydev(rootdev), getuuidbydev(dev));
1649     free(rootdev);
1650            return 0;
1651      }      }
     stat("/", &sb2);  
1652    
1653      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1654    
1655      return 1;      return 1;
1656  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1694  struct singleEntry * findEntryByPath(str
1694   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1695   if (!entry) return NULL;   if (!entry) return NULL;
1696    
1697   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1698   if (!line) return NULL;   if (!line) return NULL;
1699    
1700   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1732  struct singleEntry * findEntryByPath(str
1732    
1733   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1734      prefix = "";      prefix = "";
1735      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1736      kernel += 6;      kernel += 6;
1737   }   }
1738    
1739   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1740      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
   
1741    
1742      if (line && line->numElements >= 2 && !entry->skip) {      dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
                 rootspec = getRootSpecifier(line->elements[1].item);  
         if (!strcmp(line->elements[1].item  +  
                             ((rootspec != NULL) ? strlen(rootspec) : 0),  
                             kernel + strlen(prefix)))  
                     break;  
             }  
               
             /* have to check multiboot lines too */  
             if (entry->multiboot) {  
                 while (line && line->type != LT_MBMODULE) line = line->next;  
                 if (line && line->numElements >= 2 && !entry->skip) {  
                     rootspec = getRootSpecifier(line->elements[1].item);  
                     if (!strcmp(line->elements[1].item  +  
                                 ((rootspec != NULL) ? strlen(rootspec) : 0),  
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1743    
1744      i++;      /* check all the lines matching checkType */
1745        for (line = entry->lines; line; line = line->next) {
1746     line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1747         LT_KERNEL|LT_MBMODULE|LT_HYPER :
1748         checkType, line);
1749     if (!line) break;  /* not found in this entry */
1750    
1751     if (line && line->type != LT_MENUENTRY &&
1752     line->numElements >= 2) {
1753        rootspec = getRootSpecifier(line->elements[1].item);
1754        if (!strcmp(line->elements[1].item +
1755     ((rootspec != NULL) ? strlen(rootspec) : 0),
1756     kernel + strlen(prefix)))
1757     break;
1758     }
1759     if(line->type == LT_MENUENTRY &&
1760     !strcmp(line->elements[1].item, kernel))
1761        break;
1762        }
1763    
1764        /* make sure this entry has a kernel identifier; this skips
1765         * non-Linux boot entries (could find netbsd etc, though, which is
1766         * unfortunate)
1767         */
1768        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1769     break; /* found 'im! */
1770   }   }
1771    
1772   if (index) *index = i;   if (index) *index = i;
1773      }      }
1774    
     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);  
     }  
   
1775      return entry;      return entry;
1776  }  }
1777    
# Line 1200  void markRemovedImage(struct grubConfig Line 1850  void markRemovedImage(struct grubConfig
1850        const char * prefix) {        const char * prefix) {
1851      struct singleEntry * entry;      struct singleEntry * entry;
1852    
1853      if (!image) return;      if (!image)
1854     return;
1855    
1856        /* check and see if we're removing the default image */
1857        if (isdigit(*image)) {
1858     entry = findEntryByPath(cfg, image, prefix, NULL);
1859     if(entry)
1860        entry->skip = 1;
1861     return;
1862        }
1863    
1864      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1865   entry->skip = 1;   entry->skip = 1;
# Line 1227  void setDefaultImage(struct grubConfig * Line 1886  void setDefaultImage(struct grubConfig *
1886    
1887      /* defaultImage now points to what we'd like to use, but before any order      /* defaultImage now points to what we'd like to use, but before any order
1888         changes */         changes */
1889      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1890     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1891        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1892        return;        return;
1893    
# Line 1286  void displayEntry(struct singleEntry * e Line 1946  void displayEntry(struct singleEntry * e
1946      char * root = NULL;      char * root = NULL;
1947      int i;      int i;
1948    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1949      printf("index=%d\n", index);      printf("index=%d\n", index);
1950    
1951      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1952        if (!line) {
1953            printf("non linux entry\n");
1954            return;
1955        }
1956    
1957        printf("kernel=%s%s\n", prefix, line->elements[1].item);
1958    
1959      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1960   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1971  void displayEntry(struct singleEntry * e
1971   }   }
1972   printf("\"\n");   printf("\"\n");
1973      } else {      } else {
1974   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1975   if (line) {   if (line) {
1976      char * s;      char * s;
1977    
# Line 1334  void displayEntry(struct singleEntry * e Line 1995  void displayEntry(struct singleEntry * e
1995      }      }
1996    
1997      if (!root) {      if (!root) {
1998   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
1999   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2000      root=line->elements[1].item;      root=line->elements[1].item;
2001      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2010  void displayEntry(struct singleEntry * e
2010   printf("root=%s\n", s);   printf("root=%s\n", s);
2011      }      }
2012    
2013      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2014    
2015      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2016   printf("initrd=%s", prefix);   printf("initrd=%s", prefix);
# Line 1360  void displayEntry(struct singleEntry * e Line 2018  void displayEntry(struct singleEntry * e
2018      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2019   printf("\n");   printf("\n");
2020      }      }
2021    
2022        line = getLineByType(LT_TITLE, entry->lines);
2023        if (line) {
2024     printf("title=%s\n", line->elements[1].item);
2025        } else {
2026     char * title;
2027     line = getLineByType(LT_MENUENTRY, entry->lines);
2028     title = grub2ExtractTitle(line);
2029     if (title)
2030        printf("title=%s\n", title);
2031        }
2032  }  }
2033    
2034  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2038  int parseSysconfigGrub(int * lbaPtr, cha
2038      char * start;      char * start;
2039      char * param;      char * param;
2040    
2041      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2042      if (!in) return 1;      if (!in) return 1;
2043    
2044      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1431  int displayInfo(struct grubConfig * conf Line 2100  int displayInfo(struct grubConfig * conf
2100   return 1;   return 1;
2101      }      }
2102    
2103      /* 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
2104         be a better way */         be a better way */
2105      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2106   dumpSysconfigGrub();   dumpSysconfigGrub();
2107      } else {      } else {
2108   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2109   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2110      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2111   }   }
2112    
2113   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2114   if (line) printf("lba\n");   if (line) printf("lba\n");
2115      }      }
2116    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2125  int displayInfo(struct grubConfig * conf
2125      return 0;      return 0;
2126  }  }
2127    
2128    struct singleLine * addLineTmpl(struct singleEntry * entry,
2129     struct singleLine * tmplLine,
2130     struct singleLine * prevLine,
2131     const char * val,
2132     struct configFileInfo * cfi)
2133    {
2134        struct singleLine * newLine = lineDup(tmplLine);
2135    
2136        if (val) {
2137     /* override the inherited value with our own.
2138     * This is a little weak because it only applies to elements[1]
2139     */
2140     if (newLine->numElements > 1)
2141        removeElement(newLine, 1);
2142     insertElement(newLine, val, 1, cfi);
2143    
2144     /* but try to keep the rootspec from the template... sigh */
2145     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2146        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2147        if (rootspec != NULL) {
2148     free(newLine->elements[1].item);
2149     newLine->elements[1].item =
2150        sdupprintf("%s%s", rootspec, val);
2151        }
2152     }
2153        }
2154    
2155        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2156          newLine->elements[0].item : "");
2157    
2158        if (!entry->lines) {
2159     /* first one on the list */
2160     entry->lines = newLine;
2161        } else if (prevLine) {
2162     /* add after prevLine */
2163     newLine->next = prevLine->next;
2164     prevLine->next = newLine;
2165        }
2166    
2167        return newLine;
2168    }
2169    
2170  /* val may be NULL */  /* val may be NULL */
2171  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2172       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2173       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2174       char * val) {       const char * val) {
2175      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2176      int i;      struct keywordTypes * kw;
2177        struct singleLine tmpl;
2178    
2179      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2180   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2181      if (type != LT_TITLE || !cfi->titleBracketed)       */
2182          if (!cfi->keywords[i].key) abort();  
2183        if (type == LT_TITLE && cfi->titleBracketed) {
2184     /* we're doing a bracketed title (zipl) */
2185     tmpl.type = type;
2186     tmpl.numElements = 1;
2187     tmpl.elements = alloca(sizeof(*tmpl.elements));
2188     tmpl.elements[0].item = alloca(strlen(val)+3);
2189     sprintf(tmpl.elements[0].item, "[%s]", val);
2190     tmpl.elements[0].indent = "";
2191     val = NULL;
2192        } else if (type == LT_MENUENTRY) {
2193     char *lineend = "--class gnu-linux --class gnu --class os {";
2194     if (!val) {
2195        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2196        abort();
2197     }
2198     kw = getKeywordByType(type, cfi);
2199     if (!kw) {
2200        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2201        abort();
2202     }
2203     tmpl.indent = "";
2204     tmpl.type = type;
2205     tmpl.numElements = 3;
2206     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2207     tmpl.elements[0].item = kw->key;
2208     tmpl.elements[0].indent = alloca(2);
2209     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2210     tmpl.elements[1].item = (char *)val;
2211     tmpl.elements[1].indent = alloca(2);
2212     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2213     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2214     strcpy(tmpl.elements[2].item, lineend);
2215     tmpl.elements[2].indent = "";
2216        } else {
2217     kw = getKeywordByType(type, cfi);
2218     if (!kw) {
2219        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2220        abort();
2221     }
2222     tmpl.type = type;
2223     tmpl.numElements = val ? 2 : 1;
2224     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2225     tmpl.elements[0].item = kw->key;
2226     tmpl.elements[0].indent = alloca(2);
2227     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2228     if (val) {
2229        tmpl.elements[1].item = (char *)val;
2230        tmpl.elements[1].indent = "";
2231     }
2232        }
2233    
2234      /* 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
2235         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2236         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
2237         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2238         differently from the rest) */         differently from the rest) */
2239      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2240   line = entry->lines;   if (line->numElements) prev = line;
2241   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2242   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;  
2243      }      }
2244    
2245      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2246          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2247          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2248          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2249          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2250          line->elements[0].indent = malloc(2);   else
2251          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2252          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2253             if (menuEntry)
2254          if (val) {      tmpl.indent = "\t";
2255              line->elements[1].item = val;   else if (prev == entry->lines)
2256              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2257          }   else
2258      } 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("");  
2259      }      }
2260    
2261      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2262  }  }
2263    
2264  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2283  void removeLine(struct singleEntry * ent
2283      free(line);      free(line);
2284  }  }
2285    
2286    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2287    {
2288        struct singleLine newLine = {
2289     .indent = tmplLine->indent,
2290     .type = tmplLine->type,
2291     .next = tmplLine->next,
2292        };
2293        int firstQuotedItem = -1;
2294        int quoteLen = 0;
2295        int j;
2296        int element = 0;
2297        char *c;
2298    
2299        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2300        strcpy(c, tmplLine->elements[0].item);
2301        insertElement(&newLine, c, element++, cfi);
2302        free(c);
2303        c = NULL;
2304    
2305        for (j = 1; j < tmplLine->numElements; j++) {
2306     if (firstQuotedItem == -1) {
2307        quoteLen += strlen(tmplLine->elements[j].item);
2308        
2309        if (isquote(tmplLine->elements[j].item[0])) {
2310     firstQuotedItem = j;
2311            quoteLen += strlen(tmplLine->elements[j].indent);
2312        } else {
2313     c = malloc(quoteLen + 1);
2314     strcpy(c, tmplLine->elements[j].item);
2315     insertElement(&newLine, c, element++, cfi);
2316     free(c);
2317     quoteLen = 0;
2318        }
2319     } else {
2320        int itemlen = strlen(tmplLine->elements[j].item);
2321        quoteLen += itemlen;
2322        quoteLen += strlen(tmplLine->elements[j].indent);
2323        
2324        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2325     c = malloc(quoteLen + 1);
2326     c[0] = '\0';
2327     for (int i = firstQuotedItem; i < j+1; i++) {
2328        strcat(c, tmplLine->elements[i].item);
2329        strcat(c, tmplLine->elements[i].indent);
2330     }
2331     insertElement(&newLine, c, element++, cfi);
2332     free(c);
2333    
2334     firstQuotedItem = -1;
2335     quoteLen = 0;
2336        }
2337     }
2338        }
2339        while (tmplLine->numElements)
2340     removeElement(tmplLine, 0);
2341        if (tmplLine->elements)
2342     free(tmplLine->elements);
2343    
2344        tmplLine->numElements = newLine.numElements;
2345        tmplLine->elements = newLine.elements;
2346    }
2347    
2348    static void insertElement(struct singleLine * line,
2349      const char * item, int insertHere,
2350      struct configFileInfo * cfi)
2351    {
2352        struct keywordTypes * kw;
2353        char indent[2] = "";
2354    
2355        /* sanity check */
2356        if (insertHere > line->numElements) {
2357     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2358      insertHere, line->numElements);
2359     insertHere = line->numElements;
2360        }
2361    
2362        line->elements = realloc(line->elements, (line->numElements + 1) *
2363         sizeof(*line->elements));
2364        memmove(&line->elements[insertHere+1],
2365        &line->elements[insertHere],
2366        (line->numElements - insertHere) *
2367        sizeof(*line->elements));
2368        line->elements[insertHere].item = strdup(item);
2369    
2370        kw = getKeywordByType(line->type, cfi);
2371    
2372        if (line->numElements == 0) {
2373     indent[0] = '\0';
2374        } else if (insertHere == 0) {
2375     indent[0] = kw->nextChar;
2376        } else if (kw->separatorChar != '\0') {
2377     indent[0] = kw->separatorChar;
2378        } else {
2379     indent[0] = ' ';
2380        }
2381    
2382        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2383     /* move the end-of-line forward */
2384     line->elements[insertHere].indent =
2385        line->elements[insertHere-1].indent;
2386     line->elements[insertHere-1].indent = strdup(indent);
2387        } else {
2388     line->elements[insertHere].indent = strdup(indent);
2389        }
2390    
2391        line->numElements++;
2392    
2393        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2394          line->elements[0].item,
2395          line->elements[insertHere].item,
2396          line->elements[insertHere].indent,
2397          insertHere);
2398    }
2399    
2400    static void removeElement(struct singleLine * line, int removeHere) {
2401        int i;
2402    
2403        /* sanity check */
2404        if (removeHere >= line->numElements) return;
2405    
2406        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2407          removeHere, line->elements[removeHere].item);
2408    
2409        free(line->elements[removeHere].item);
2410    
2411        if (removeHere > 1) {
2412     /* previous argument gets this argument's post-indentation */
2413     free(line->elements[removeHere-1].indent);
2414     line->elements[removeHere-1].indent =
2415        line->elements[removeHere].indent;
2416        } else {
2417     free(line->elements[removeHere].indent);
2418        }
2419    
2420        /* now collapse the array, but don't bother to realloc smaller */
2421        for (i = removeHere; i < line->numElements - 1; i++)
2422     line->elements[i] = line->elements[i + 1];
2423    
2424        line->numElements--;
2425    }
2426    
2427  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2428      char * first, * second;      char * first, * second;
2429      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2446  int updateActualImage(struct grubConfig
2446      struct singleEntry * entry;      struct singleEntry * entry;
2447      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2448      int index = 0;      int index = 0;
2449      int i, j, k;      int i, k;
2450      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2451      const char ** arg;      const char ** arg;
2452      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2453      int firstElement;      int firstElement;
2454      int *usedElements, *usedArgs;      int *usedElements;
2455        int doreplace;
2456    
2457      if (!image) return 0;      if (!image) return 0;
2458    
# Line 1609  int updateActualImage(struct grubConfig Line 2479  int updateActualImage(struct grubConfig
2479   }   }
2480      }      }
2481    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2482    
2483      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2484   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2485    
2486      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2487   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2488    
2489      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2490    
2491      k = 0;   if (multibootArgs && !entry->multiboot)
2492      for (arg = newArgs; *arg; arg++)      continue;
2493          k++;  
2494      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2495     * LT_KERNELARGS, use that.  Otherwise use
2496     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2497     */
2498     if (useKernelArgs) {
2499        line = getLineByType(LT_KERNELARGS, entry->lines);
2500        if (!line) {
2501     /* no LT_KERNELARGS, need to add it */
2502     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2503           cfg->secondaryIndent, NULL);
2504        }
2505        firstElement = 1;
2506    
2507      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2508   index++;      line = getLineByType(LT_HYPER, entry->lines);
2509        if (!line) {
2510     /* a multiboot entry without LT_HYPER? */
2511     continue;
2512        }
2513        firstElement = 2;
2514    
2515   line = entry->lines;   } else {
2516   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2517   if (!line) continue;      if (!line) {
2518   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2519     continue;
2520          if (entry->multiboot && !multibootArgs) {      }
2521              /* 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;  
2522   }   }
2523    
2524   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2525      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2526      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2527     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2528        /* this is a multiboot entry, make sure there's
2529         * -- on the args line
2530         */
2531        for (i = firstElement; i < line->numElements; i++) {
2532     if (!strcmp(line->elements[i].item, "--"))
2533        break;
2534        }
2535        if (i == line->numElements) {
2536     /* assume all existing args are kernel args,
2537     * prepend -- to make it official
2538     */
2539     insertElement(line, "--", firstElement, cfg->cfi);
2540     i = firstElement;
2541        }
2542        if (!multibootArgs) {
2543     /* kernel args start after the -- */
2544     firstElement = i + 1;
2545        }
2546     } else if (cfg->cfi->mbConcatArgs) {
2547        /* this is a non-multiboot entry, remove hyper args */
2548        for (i = firstElement; i < line->numElements; i++) {
2549     if (!strcmp(line->elements[i].item, "--"))
2550        break;
2551        }
2552        if (i < line->numElements) {
2553     /* remove args up to -- */
2554     while (strcmp(line->elements[firstElement].item, "--"))
2555        removeElement(line, firstElement);
2556     /* remove -- */
2557     removeElement(line, firstElement);
2558        }
2559   }   }
2560    
2561          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2562    
2563          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2564   for (arg = newArgs; *arg; arg++) {  
2565              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2566      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2567     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2568        !strcmp(line->elements[i].item, "--"))
2569     {
2570        /* reached the end of hyper args, insert here */
2571        doreplace = 0;
2572        break;  
2573     }
2574                  if (usedElements[i])                  if (usedElements[i])
2575                      continue;                      continue;
2576   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2577                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2578      break;      break;
2579                  }                  }
2580              }              }
     chptr = strchr(*arg, '=');  
2581    
2582      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2583   /* replace */   /* direct replacement */
2584   free(line->elements[i].item);   free(line->elements[i].item);
2585   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("");  
  }  
2586    
2587   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2588   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2589      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2590   /* append */   if (rootLine) {
2591   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2592   (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(" ");  
2593   } else {   } else {
2594      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2595         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2596   }   }
2597        }
2598    
2599   line->numElements++;      else {
2600     /* insert/append */
2601     insertElement(line, *arg, i, cfg->cfi);
2602     usedElements = realloc(usedElements, line->numElements *
2603           sizeof(*usedElements));
2604     memmove(&usedElements[i + 1], &usedElements[i],
2605     line->numElements - i - 1);
2606     usedElements[i] = 1;
2607    
2608   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2609     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2610     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2611   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2612      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2613      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2614   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2615   }   }
2616      }      }
             k++;  
2617   }   }
2618    
2619          free(usedElements);          free(usedElements);
2620    
  /* 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? */  
2621   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2622      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2623   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2624        !strcmp(line->elements[i].item, "--"))
2625        /* reached the end of hyper args, stop here */
2626        break;
2627     if (!argMatch(line->elements[i].item, *arg)) {
2628        removeElement(line, i);
2629      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;  
2630   }   }
2631        }
2632   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2633        if (useRoot && !strncmp(*arg, "root=", 5)) {
2634   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2635      line->elements[j - 1] = line->elements[j];   if (rootLine)
2636        removeLine(entry, rootLine);
  line->numElements--;  
2637      }      }
2638   }   }
2639    
# Line 1760  int updateActualImage(struct grubConfig Line 2644  int updateActualImage(struct grubConfig
2644   }   }
2645      }      }
2646    
     free(usedArgs);  
2647      free(newArgs);      free(newArgs);
2648      free(oldArgs);      free(oldArgs);
2649    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2669  int updateImage(struct grubConfig * cfg,
2669      return rc;      return rc;
2670  }  }
2671    
2672    int updateInitrd(struct grubConfig * cfg, const char * image,
2673                     const char * prefix, const char * initrd) {
2674        struct singleEntry * entry;
2675        struct singleLine * line, * kernelLine, *endLine = NULL;
2676        int index = 0;
2677    
2678        if (!image) return 0;
2679    
2680        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2681            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2682            if (!kernelLine) continue;
2683    
2684            line = getLineByType(LT_INITRD, entry->lines);
2685            if (line)
2686                removeLine(entry, line);
2687            if (prefix) {
2688                int prefixLen = strlen(prefix);
2689                if (!strncmp(initrd, prefix, prefixLen))
2690                    initrd += prefixLen;
2691            }
2692     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2693     if (endLine)
2694        removeLine(entry, endLine);
2695            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2696            if (!line)
2697        return 1;
2698     if (endLine) {
2699        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2700                if (!line)
2701     return 1;
2702     }
2703    
2704            break;
2705        }
2706    
2707        return 0;
2708    }
2709    
2710  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2711      int fd;      int fd;
2712      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 2730  int checkDeviceBootloader(const char * d
2730      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
2731   return 0;   return 0;
2732    
2733      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
2734   offset = boot[2] + 2;   offset = boot[2] + 2;
2735      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
2736   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
2737      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
2738   offset = boot[1] + 2;        offset = boot[1] + 2;
2739            /*
2740     * it looks like grub, when copying stage1 into the mbr, patches stage1
2741     * right after the JMP location, replacing other instructions such as
2742     * JMPs for NOOPs. So, relax the check a little bit by skipping those
2743     * different bytes.
2744     */
2745          if ((bootSect[offset + 1] == NOOP_OPCODE)
2746      && (bootSect[offset + 2] == NOOP_OPCODE)) {
2747     offset = offset + 3;
2748          }
2749      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
2750   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
2751      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 2887  int checkForLilo(struct grubConfig * con
2887      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
2888  }  }
2889    
2890    int checkForGrub2(struct grubConfig * config) {
2891        if (!access("/etc/grub.d/", R_OK))
2892     return 2;
2893    
2894        return 1;
2895    }
2896    
2897  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
2898      int fd;      int fd;
2899      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1976  int checkForGrub(struct grubConfig * con Line 2914  int checkForGrub(struct grubConfig * con
2914      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
2915   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2916   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
2917     close(fd);
2918     return 1;
2919        }
2920        close(fd);
2921    
2922        return checkDeviceBootloader(boot, bootSect);
2923    }
2924    
2925    int checkForExtLinux(struct grubConfig * config) {
2926        int fd;
2927        unsigned char bootSect[512];
2928        char * boot;
2929        char executable[] = "/boot/extlinux/extlinux";
2930    
2931        printf("entered: checkForExtLinux()\n");
2932    
2933        if (parseSysconfigGrub(NULL, &boot))
2934     return 0;
2935    
2936        /* assume grub is not installed -- not an error condition */
2937        if (!boot)
2938     return 0;
2939    
2940        fd = open(executable, O_RDONLY);
2941        if (fd < 0)
2942     /* this doesn't exist if grub hasn't been installed */
2943     return 0;
2944    
2945        if (read(fd, bootSect, 512) != 512) {
2946     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
2947     executable, strerror(errno));
2948   return 1;   return 1;
2949      }      }
2950      close(fd);      close(fd);
# Line 1994  static char * getRootSpecifier(char * st Line 2963  static char * getRootSpecifier(char * st
2963      return rootspec;      return rootspec;
2964  }  }
2965    
2966    static char * getInitrdVal(struct grubConfig * config,
2967       const char * prefix, struct singleLine *tmplLine,
2968       const char * newKernelInitrd,
2969       const char ** extraInitrds, int extraInitrdCount)
2970    {
2971        char *initrdVal, *end;
2972        int i;
2973        size_t totalSize;
2974        size_t prefixLen;
2975        char separatorChar;
2976    
2977        prefixLen = strlen(prefix);
2978        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
2979    
2980        for (i = 0; i < extraInitrdCount; i++) {
2981     totalSize += sizeof(separatorChar);
2982     totalSize += strlen(extraInitrds[i]) - prefixLen;
2983        }
2984    
2985        initrdVal = end = malloc(totalSize);
2986    
2987        end = stpcpy (end, newKernelInitrd + prefixLen);
2988    
2989        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
2990        for (i = 0; i < extraInitrdCount; i++) {
2991     const char *extraInitrd;
2992     int j;
2993    
2994     extraInitrd = extraInitrds[i] + prefixLen;
2995     /* Don't add entries that are already there */
2996     if (tmplLine != NULL) {
2997        for (j = 2; j < tmplLine->numElements; j++)
2998     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
2999        break;
3000    
3001        if (j != tmplLine->numElements)
3002     continue;
3003     }
3004    
3005     *end++ = separatorChar;
3006     end = stpcpy(end, extraInitrd);
3007        }
3008    
3009        return initrdVal;
3010    }
3011    
3012  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3013           const char * prefix,           const char * prefix,
3014   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3015   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3016                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3017                     const char * newMBKernel, const char * newMBKernelArgs) {
3018      struct singleEntry * new;      struct singleEntry * new;
3019      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3020      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3021      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3022    
3023      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3024    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3048  int addNewKernel(struct grubConfig * con
3048      config->entries = new;      config->entries = new;
3049    
3050      /* copy/update from the template */      /* copy/update from the template */
3051      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3052        if (newKernelInitrd)
3053     needs |= NEED_INITRD;
3054      if (newMBKernel) {      if (newMBKernel) {
3055          needs |= KERNEL_MB;          needs |= NEED_MB;
3056          new->multiboot = 1;          new->multiboot = 1;
3057      }      }
3058    
3059      if (template) {      if (template) {
3060   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3061      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3062      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3063   indent = tmplLine->indent;   {
3064        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3065    
3066      /* skip comments */      /* skip comments */
3067      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3068      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3069      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3070    
3071      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3072      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3073     if (!template->multiboot && (needs & NEED_MB)) {
3074              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3075                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3076                  struct singleLine *l;       * hypervisor at the same time.
3077                  needs &= ~ KERNEL_MB;       */
3078        if (config->cfi->mbHyperFirst) {
3079                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3080                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3081                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3082                      newMBKernel + strlen(prefix));
3083                  tmplLine = lastLine;   /* set up for adding the kernel line */
3084                  if (!new->lines) {   free(tmplLine->indent);
3085                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3086                  } else {   needs &= ~NEED_MB;
3087                      newLine->next = l;      }
3088                      newLine = l;      if (needs & NEED_KERNEL) {
3089                  }   /* use addLineTmpl to preserve line elements,
3090                  continue;   * otherwise we could just call addLine.  Unfortunately
3091              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3092                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3093                  continue; /* don't need multiboot kernel here */   * change below.
3094              }   */
3095     struct keywordTypes * mbm_kw =
3096        getKeywordByType(LT_MBMODULE, config->cfi);
3097     if (mbm_kw) {
3098        tmplLine->type = LT_MBMODULE;
3099        free(tmplLine->elements[0].item);
3100        tmplLine->elements[0].item = strdup(mbm_kw->key);
3101     }
3102     newLine = addLineTmpl(new, tmplLine, newLine,
3103          newKernelPath + strlen(prefix), config->cfi);
3104     needs &= ~NEED_KERNEL;
3105        }
3106        if (needs & NEED_MB) { /* !mbHyperFirst */
3107     newLine = addLine(new, config->cfi, LT_HYPER,
3108      config->secondaryIndent,
3109      newMBKernel + strlen(prefix));
3110     needs &= ~NEED_MB;
3111        }
3112     } else if (needs & NEED_KERNEL) {
3113        newLine = addLineTmpl(new, tmplLine, newLine,
3114      newKernelPath + strlen(prefix), config->cfi);
3115        needs &= ~NEED_KERNEL;
3116     }
3117    
3118      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3119   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3120   new->lines = newLine;   if (needs & NEED_MB) {
3121      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3122   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3123   newLine = newLine->next;      needs &= ~NEED_MB;
3124      }   }
3125    
3126        } else if (tmplLine->type == LT_MBMODULE &&
3127           tmplLine->numElements >= 2) {
3128     if (new->multiboot) {
3129        if (needs & NEED_KERNEL) {
3130     newLine = addLineTmpl(new, tmplLine, newLine,
3131          newKernelPath +
3132          strlen(prefix), config->cfi);
3133     needs &= ~NEED_KERNEL;
3134        } else if (config->cfi->mbInitRdIsModule &&
3135           (needs & NEED_INITRD)) {
3136     char *initrdVal;
3137     initrdVal = getInitrdVal(config, prefix, tmplLine,
3138     newKernelInitrd, extraInitrds,
3139     extraInitrdCount);
3140     newLine = addLineTmpl(new, tmplLine, newLine,
3141          initrdVal, config->cfi);
3142     free(initrdVal);
3143     needs &= ~NEED_INITRD;
3144        }
3145     } else if (needs & NEED_KERNEL) {
3146        /* template is multi but new is not,
3147         * insert the kernel in the first module slot
3148         */
3149        tmplLine->type = LT_KERNEL;
3150        free(tmplLine->elements[0].item);
3151        tmplLine->elements[0].item =
3152     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3153        newLine = addLineTmpl(new, tmplLine, newLine,
3154      newKernelPath + strlen(prefix), config->cfi);
3155        needs &= ~NEED_KERNEL;
3156     } else if (needs & NEED_INITRD) {
3157        char *initrdVal;
3158        /* template is multi but new is not,
3159         * insert the initrd in the second module slot
3160         */
3161        tmplLine->type = LT_INITRD;
3162        free(tmplLine->elements[0].item);
3163        tmplLine->elements[0].item =
3164     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3165        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3166        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3167        free(initrdVal);
3168        needs &= ~NEED_INITRD;
3169     }
3170    
     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));  
                 }  
3171      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3172      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3173   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3174   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3175                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3176                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3177                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3178                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3179                  }       */
3180                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3181                  if (rootspec != NULL) {   char *initrdVal;
3182                      newLine->elements[1].item = sdupprintf("%s%s",  
3183                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3184                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3185                                                             strlen(prefix));    config->secondaryIndent,
3186                  } else {    initrdVal);
3187                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3188                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3189                  }      }
3190              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3191                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3192   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3193                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3194                      free(newLine->elements[0].item);      free(initrdVal);
3195                      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);  
3196   }   }
3197    
3198   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3199   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3200   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3201     char *nkt = malloc(strlen(newKernelTitle)+3);
3202     strcpy(nkt, "'");
3203     strcat(nkt, newKernelTitle);
3204     strcat(nkt, "'");
3205     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3206     free(nkt);
3207     needs &= ~NEED_TITLE;
3208      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3209                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3210                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3211                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3212                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3213                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3214                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3215                                             newLine->numElements);     config->cfi->titleBracketed) {
3216        /* addLineTmpl doesn't handle titleBracketed */
3217                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3218                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3219                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3220                  newLine->numElements = 1;   }
3221              }      } else if (tmplLine->type == LT_ECHO) {
3222        requote(tmplLine, config->cfi);
3223        static const char *prefix = "'Loading ";
3224        if (tmplLine->numElements > 1 &&
3225        strstr(tmplLine->elements[1].item, prefix) &&
3226        masterLine->next && masterLine->next->type == LT_KERNEL) {
3227     char *newTitle = malloc(strlen(prefix) +
3228     strlen(newKernelTitle) + 2);
3229    
3230     strcpy(newTitle, prefix);
3231     strcat(newTitle, newKernelTitle);
3232     strcat(newTitle, "'");
3233     newLine = addLine(new, config->cfi, LT_ECHO,
3234     tmplLine->indent, newTitle);
3235     free(newTitle);
3236        } else {
3237     /* pass through other lines from the template */
3238     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3239     config->cfi);
3240        }
3241        } else {
3242     /* pass through other lines from the template */
3243     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3244        }
3245   }   }
3246    
3247      } else {      } else {
3248   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3249      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3250     */
3251     switch (config->cfi->entryStart) {
3252        case LT_KERNEL:
3253     if (new->multiboot && config->cfi->mbHyperFirst) {
3254        /* fall through to LT_HYPER */
3255     } else {
3256        newLine = addLine(new, config->cfi, LT_KERNEL,
3257          config->primaryIndent,
3258          newKernelPath + strlen(prefix));
3259        needs &= ~NEED_KERNEL;
3260        break;
3261     }
3262    
3263        case LT_HYPER:
3264     newLine = addLine(new, config->cfi, LT_HYPER,
3265      config->primaryIndent,
3266      newMBKernel + strlen(prefix));
3267     needs &= ~NEED_MB;
3268   break;   break;
         }  
3269    
3270   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3271      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3272       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3273       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3274      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3275       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3276      default:        config->primaryIndent, nkt);
3277                  /* zipl strikes again */   free(nkt);
3278                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3279                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3280                      chptr = newKernelTitle;   break;
3281                      type = LT_TITLE;      }
3282                      break;      case LT_TITLE:
3283                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3284                      abort();   char * templabel;
3285                  }   int x = 0, y = 0;
3286   }  
3287     templabel = strdup(newKernelTitle);
3288     while( templabel[x]){
3289     if( templabel[x] == ' ' ){
3290     y = x;
3291     while( templabel[y] ){
3292     templabel[y] = templabel[y+1];
3293     y++;
3294     }
3295     }
3296     x++;
3297     }
3298     newLine = addLine(new, config->cfi, LT_TITLE,
3299      config->primaryIndent, templabel);
3300     free(templabel);
3301     }else{
3302     newLine = addLine(new, config->cfi, LT_TITLE,
3303      config->primaryIndent, newKernelTitle);
3304     }
3305     needs &= ~NEED_TITLE;
3306     break;
3307    
3308   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3309   new->lines = newLine;   abort();
3310     }
3311      }      }
3312    
3313      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3314          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3315              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3316                                config->secondaryIndent,       */
3317                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3318          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3319              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3320                                config->secondaryIndent,    newKernelTitle);
3321                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3322          /* don't need to check for title as it's guaranteed to have been      }
3323           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3324           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3325          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3326              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3327                                config->secondaryIndent,   needs &= ~NEED_MB;
3328                                newKernelInitrd + strlen(prefix));      }
3329      } else {      if (needs & NEED_KERNEL) {
3330          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3331              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3332                                config->secondaryIndent,        config->cfi)) ?
3333                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3334          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3335              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3336                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3337                                newKernelTitle);      }
3338          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3339              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3340                                config->secondaryIndent,    config->secondaryIndent,
3341                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3342     needs &= ~NEED_MB;
3343        }
3344        if (needs & NEED_INITRD) {
3345     char *initrdVal;
3346     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3347     newLine = addLine(new, config->cfi,
3348      (new->multiboot && getKeywordByType(LT_MBMODULE,
3349          config->cfi)) ?
3350      LT_MBMODULE : LT_INITRD,
3351      config->secondaryIndent,
3352      initrdVal);
3353     free(initrdVal);
3354     needs &= ~NEED_INITRD;
3355        }
3356        if (needs & NEED_END) {
3357     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3358     config->secondaryIndent, NULL);
3359     needs &= ~NEED_END;
3360        }
3361    
3362        if (needs) {
3363     printf(_("grubby: needs=%d, aborting\n"), needs);
3364     abort();
3365      }      }
3366    
3367      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3370  int addNewKernel(struct grubConfig * con
3370      return 0;      return 0;
3371  }  }
3372    
3373    static void traceback(int signum)
3374    {
3375        void *array[40];
3376        size_t size;
3377    
3378        signal(SIGSEGV, SIG_DFL);
3379        memset(array, '\0', sizeof (array));
3380        size = backtrace(array, 40);
3381    
3382        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3383                (unsigned long)size);
3384        backtrace_symbols_fd(array, size, STDERR_FILENO);
3385        exit(1);
3386    }
3387    
3388  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3389      poptContext optCon;      poptContext optCon;
3390      char * grubConfig = NULL;      const char * grubConfig = NULL;
3391      char * outputFile = NULL;      char * outputFile = NULL;
3392      int arg = 0;      int arg = 0;
3393      int flags = 0;      int flags = 0;
3394      int badImageOkay = 0;      int badImageOkay = 0;
3395        int configureGrub2 = 0;
3396      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3397      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3398        int configureExtLinux = 0;
3399      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3400        int extraInitrdCount = 0;
3401      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3402      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3403      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3413  int main(int argc, const char ** argv) {
3413      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3414      char * removeArgs = NULL;      char * removeArgs = NULL;
3415      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3416        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3417      const char * chptr = NULL;      const char * chptr = NULL;
3418      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3419      struct grubConfig * config;      struct grubConfig * config;
3420      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3421      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3422      int displayDefault = 0;      int displayDefault = 0;
3423        int displayDefaultIndex = 0;
3424        int displayDefaultTitle = 0;
3425      struct poptOption options[] = {      struct poptOption options[] = {
3426   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3427      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2335  int main(int argc, const char ** argv) { Line 3452  int main(int argc, const char ** argv) {
3452        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3453        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3454        "template"), NULL },        "template"), NULL },
3455     { "debug", 0, 0, &debug, 0,
3456        _("print debugging information for failures") },
3457   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3458      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3459     { "default-index", 0, 0, &displayDefaultIndex, 0,
3460        _("display the index of the default kernel") },
3461     { "default-title", 0, 0, &displayDefaultTitle, 0,
3462        _("display the title of the default kernel") },
3463   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3464      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3465     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3466        _("configure extlinux bootloader (from syslinux)") },
3467   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3468      _("configure grub bootloader") },      _("configure grub bootloader") },
3469     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3470        _("configure grub2 bootloader") },
3471   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3472      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3473      _("kernel-path") },      _("kernel-path") },
3474   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3475      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3476     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3477        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3478   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3479      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3480   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3511  int main(int argc, const char ** argv) {
3511   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3512      };      };
3513    
3514        useextlinuxmenu=0;
3515    
3516        signal(SIGSEGV, traceback);
3517    
3518      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3519      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3520    
# Line 2391  int main(int argc, const char ** argv) { Line 3524  int main(int argc, const char ** argv) {
3524      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3525      exit(0);      exit(0);
3526      break;      break;
3527      case 'i':
3528        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3529         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3530        } else {
3531     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3532     return 1;
3533        }
3534        break;
3535   }   }
3536      }      }
3537    
# Line 2406  int main(int argc, const char ** argv) { Line 3547  int main(int argc, const char ** argv) {
3547   return 1;   return 1;
3548      }      }
3549    
3550      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3551   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3552     configureExtLinux ) > 1) {
3553   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3554   return 1;   return 1;
3555      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3556   fprintf(stderr,   fprintf(stderr,
3557      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3558   return 1;   return 1;
3559        } else if (configureGrub2) {
3560     cfi = &grub2ConfigType;
3561      } else if (configureLilo) {      } else if (configureLilo) {
3562   cfi = &liloConfigType;   cfi = &liloConfigType;
3563      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3570  int main(int argc, const char ** argv) {
3570          cfi = &siloConfigType;          cfi = &siloConfigType;
3571      } else if (configureZipl) {      } else if (configureZipl) {
3572          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3573        } else if (configureExtLinux) {
3574     cfi = &extlinuxConfigType;
3575     useextlinuxmenu=1;
3576      }      }
3577    
3578      if (!cfi) {      if (!cfi) {
3579            if (grub2FindConfig(&grub2ConfigType))
3580        cfi = &grub2ConfigType;
3581     else
3582        #ifdef __ia64__        #ifdef __ia64__
3583   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3584        #elif __powerpc__        #elif __powerpc__
3585   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3586        #elif __sparc__        #elif __sparc__
3587          cfi = &siloConfigType;              cfi = &siloConfigType;
3588        #elif __s390__        #elif __s390__
3589          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3590        #elif __s390x__        #elif __s390x__
3591          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3592        #else        #else
3593   cfi = &grubConfigType;      cfi = &grubConfigType;
3594        #endif        #endif
3595      }      }
3596    
3597      if (!grubConfig)      if (!grubConfig) {
3598   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3599        grubConfig = cfi->findConfig(cfi);
3600     if (!grubConfig)
3601        grubConfig = cfi->defaultConfig;
3602        }
3603    
3604      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3605    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3606    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3607   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3608    "specified option"));    "specified option"));
3609   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3619  int main(int argc, const char ** argv) {
3619      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3620   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3621   return 1;   return 1;
3622      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3623    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3624    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3625   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3626   return 1;   return 1;
3627      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3646  int main(int argc, const char ** argv) {
3646   defaultKernel = NULL;   defaultKernel = NULL;
3647      }      }
3648    
3649      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3650   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3651   "is used\n"));   "is used\n"));
3652   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3654  int main(int argc, const char ** argv) {
3654    
3655      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3656   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3657          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3658   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3659   return 1;   return 1;
3660      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3674  int main(int argc, const char ** argv) {
3674   bootPrefix = "";   bootPrefix = "";
3675      }      }
3676    
3677        if (!cfi->mbAllowExtraInitRds &&
3678     extraInitrdCount > 0) {
3679     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3680     return 1;
3681        }
3682    
3683      if (bootloaderProbe) {      if (bootloaderProbe) {
3684   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, erc = 0;
3685   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig;
3686    
3687   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
3688      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
3689        gconfig = readConfig(grub2config, &grub2ConfigType);
3690        if (!gconfig)
3691     gr2c = 1;
3692        else
3693     gr2c = checkForGrub2(gconfig);
3694     }
3695    
3696     const char *grubconfig = grubFindConfig(&grubConfigType);
3697     if (!access(grubconfig, F_OK)) {
3698        gconfig = readConfig(grubconfig, &grubConfigType);
3699      if (!gconfig)      if (!gconfig)
3700   grc = 1;   grc = 1;
3701      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 3710  int main(int argc, const char ** argv) {
3710   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
3711   }   }
3712    
3713   if (lrc == 1 || grc == 1) return 1;   if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
3714        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
3715        if (!lconfig)
3716     erc = 1;
3717        else
3718     erc = checkForExtLinux(lconfig);
3719     }
3720    
3721     if (lrc == 1 || grc == 1 || gr2c == 1) return 1;
3722    
3723   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
3724     if (gr2c == 2) printf("grub2\n");
3725   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
3726     if (erc == 2) printf("extlinux\n");
3727    
3728   return 0;   return 0;
3729      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 3741  int main(int argc, const char ** argv) {
3741   if (!entry) return 0;   if (!entry) return 0;
3742   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
3743    
3744   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
3745   if (!line) return 0;   if (!line) return 0;
3746    
3747          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 3749  int main(int argc, const char ** argv) {
3749                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
3750    
3751   return 0;   return 0;
3752    
3753        } else if (displayDefaultTitle) {
3754     struct singleLine * line;
3755     struct singleEntry * entry;
3756    
3757     if (config->defaultImage == -1) return 0;
3758     entry = findEntryByIndex(config, config->defaultImage);
3759     if (!entry) return 0;
3760    
3761     if (!configureGrub2) {
3762      line = getLineByType(LT_TITLE, entry->lines);
3763      if (!line) return 0;
3764      printf("%s\n", line->elements[1].item);
3765    
3766     } else {
3767      char * title;
3768    
3769      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
3770      line = getLineByType(LT_MENUENTRY, entry->lines);
3771      if (!line) return 0;
3772      title = grub2ExtractTitle(line);
3773      if (title)
3774        printf("%s\n", title);
3775     }
3776     return 0;
3777    
3778        } else if (displayDefaultIndex) {
3779            if (config->defaultImage == -1) return 0;
3780            printf("%i\n", config->defaultImage);
3781    
3782      } else if (kernelInfo)      } else if (kernelInfo)
3783   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
3784    
# Line 2585  int main(int argc, const char ** argv) { Line 3794  int main(int argc, const char ** argv) {
3794      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
3795      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
3796                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
3797        if (updateKernelPath && newKernelInitrd) {
3798                if (updateInitrd(config, updateKernelPath, bootPrefix,
3799                                 newKernelInitrd)) return 1;
3800        }
3801      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
3802                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
3803                         (const char **)extraInitrds, extraInitrdCount,
3804                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
3805            
3806    
# Line 2597  int main(int argc, const char ** argv) { Line 3811  int main(int argc, const char ** argv) {
3811      }      }
3812    
3813      if (!outputFile)      if (!outputFile)
3814   outputFile = grubConfig;   outputFile = (char *)grubConfig;
3815    
3816      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
3817  }  }

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