Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1854 by niro, Mon Jul 2 13:12:32 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     "/boot/grub/grub.conf",
168     "/boot/grub/menu.lst",
169     "/etc/grub.conf",
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        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
1958     printf("kernel=%s\n", line->elements[1].item);
1959        else
1960     printf("kernel=%s%s\n", prefix, line->elements[1].item);
1961    
1962      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1963   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1974  void displayEntry(struct singleEntry * e
1974   }   }
1975   printf("\"\n");   printf("\"\n");
1976      } else {      } else {
1977   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1978   if (line) {   if (line) {
1979      char * s;      char * s;
1980    
# Line 1334  void displayEntry(struct singleEntry * e Line 1998  void displayEntry(struct singleEntry * e
1998      }      }
1999    
2000      if (!root) {      if (!root) {
2001   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2002   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2003      root=line->elements[1].item;      root=line->elements[1].item;
2004      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2013  void displayEntry(struct singleEntry * e
2013   printf("root=%s\n", s);   printf("root=%s\n", s);
2014      }      }
2015    
2016      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2017    
2018      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2019   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2020        printf("initrd=");
2021     else
2022        printf("initrd=%s", prefix);
2023    
2024   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2025      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2026   printf("\n");   printf("\n");
2027      }      }
2028    
2029        line = getLineByType(LT_TITLE, entry->lines);
2030        if (line) {
2031     printf("title=%s\n", line->elements[1].item);
2032        } else {
2033     char * title;
2034     line = getLineByType(LT_MENUENTRY, entry->lines);
2035     title = grub2ExtractTitle(line);
2036     if (title)
2037        printf("title=%s\n", title);
2038        }
2039    }
2040    
2041    int isSuseSystem(void) {
2042        const char * path;
2043        const static char default_path[] = "/etc/SuSE-release";
2044    
2045        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2046     path = default_path;
2047    
2048        if (!access(path, R_OK))
2049     return 1;
2050        return 0;
2051    }
2052    
2053    int isSuseGrubConf(const char * path) {
2054        FILE * grubConf;
2055        char * line = NULL;
2056        size_t len = 0, res = 0;
2057    
2058        grubConf = fopen(path, "r");
2059        if (!grubConf) {
2060            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2061     return 0;
2062        }
2063    
2064        while ((res = getline(&line, &len, grubConf)) != -1) {
2065     if (!strncmp(line, "setup", 5)) {
2066        fclose(grubConf);
2067        free(line);
2068        return 1;
2069     }
2070        }
2071    
2072        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2073          path);
2074    
2075        fclose(grubConf);
2076        free(line);
2077        return 0;
2078    }
2079    
2080    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2081        FILE * grubConf;
2082        char * line = NULL;
2083        size_t res = 0, len = 0;
2084    
2085        if (!path) return 1;
2086        if (!lbaPtr) return 1;
2087    
2088        grubConf = fopen(path, "r");
2089        if (!grubConf) return 1;
2090    
2091        while ((res = getline(&line, &len, grubConf)) != -1) {
2092     if (line[res - 1] == '\n')
2093        line[res - 1] = '\0';
2094     else if (len > res)
2095        line[res] = '\0';
2096     else {
2097        line = realloc(line, res + 1);
2098        line[res] = '\0';
2099     }
2100    
2101     if (!strncmp(line, "setup", 5)) {
2102        if (strstr(line, "--force-lba")) {
2103            *lbaPtr = 1;
2104        } else {
2105            *lbaPtr = 0;
2106        }
2107        dbgPrintf("lba: %i\n", *lbaPtr);
2108        break;
2109     }
2110        }
2111    
2112        free(line);
2113        fclose(grubConf);
2114        return 0;
2115    }
2116    
2117    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2118        FILE * grubConf;
2119        char * line = NULL;
2120        size_t res = 0, len = 0;
2121        char * lastParamPtr = NULL;
2122        char * secLastParamPtr = NULL;
2123        char installDeviceNumber = '\0';
2124        char * bounds = NULL;
2125    
2126        if (!path) return 1;
2127        if (!devicePtr) return 1;
2128    
2129        grubConf = fopen(path, "r");
2130        if (!grubConf) return 1;
2131    
2132        while ((res = getline(&line, &len, grubConf)) != -1) {
2133     if (strncmp(line, "setup", 5))
2134        continue;
2135    
2136     if (line[res - 1] == '\n')
2137        line[res - 1] = '\0';
2138     else if (len > res)
2139        line[res] = '\0';
2140     else {
2141        line = realloc(line, res + 1);
2142        line[res] = '\0';
2143     }
2144    
2145     lastParamPtr = bounds = line + res;
2146    
2147     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2148     while (!isspace(*lastParamPtr))
2149        lastParamPtr--;
2150     lastParamPtr++;
2151    
2152     secLastParamPtr = lastParamPtr - 2;
2153     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2154    
2155     if (lastParamPtr + 3 > bounds) {
2156        dbgPrintf("lastParamPtr going over boundary");
2157        fclose(grubConf);
2158        free(line);
2159        return 1;
2160     }
2161     if (!strncmp(lastParamPtr, "(hd", 3))
2162        lastParamPtr += 3;
2163     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2164    
2165     /*
2166     * Second last parameter will decide wether last parameter is
2167     * an IMAGE_DEVICE or INSTALL_DEVICE
2168     */
2169     while (!isspace(*secLastParamPtr))
2170        secLastParamPtr--;
2171     secLastParamPtr++;
2172    
2173     if (secLastParamPtr + 3 > bounds) {
2174        dbgPrintf("secLastParamPtr going over boundary");
2175        fclose(grubConf);
2176        free(line);
2177        return 1;
2178     }
2179     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2180     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2181        secLastParamPtr += 3;
2182        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2183        installDeviceNumber = *secLastParamPtr;
2184     } else {
2185        installDeviceNumber = *lastParamPtr;
2186     }
2187    
2188     *devicePtr = malloc(6);
2189     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2190     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2191     fclose(grubConf);
2192     free(line);
2193     return 0;
2194        }
2195    
2196        free(line);
2197        fclose(grubConf);
2198        return 1;
2199    }
2200    
2201    int grubGetBootFromDeviceMap(const char * device,
2202         char ** bootPtr) {
2203        FILE * deviceMap;
2204        char * line = NULL;
2205        size_t res = 0, len = 0;
2206        char * devicePtr;
2207        char * bounds = NULL;
2208        const char * path;
2209        const static char default_path[] = "/boot/grub/device.map";
2210    
2211        if (!device) return 1;
2212        if (!bootPtr) return 1;
2213    
2214        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2215     path = default_path;
2216    
2217        dbgPrintf("opening grub device.map file from: %s\n", path);
2218        deviceMap = fopen(path, "r");
2219        if (!deviceMap)
2220     return 1;
2221    
2222        while ((res = getline(&line, &len, deviceMap)) != -1) {
2223            if (!strncmp(line, "#", 1))
2224        continue;
2225    
2226     if (line[res - 1] == '\n')
2227        line[res - 1] = '\0';
2228     else if (len > res)
2229        line[res] = '\0';
2230     else {
2231        line = realloc(line, res + 1);
2232        line[res] = '\0';
2233     }
2234    
2235     devicePtr = line;
2236     bounds = line + res;
2237    
2238     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2239        devicePtr++;
2240     dbgPrintf("device: %s\n", devicePtr);
2241    
2242     if (!strncmp(devicePtr, device, strlen(device))) {
2243        devicePtr += strlen(device);
2244        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2245            devicePtr++;
2246    
2247        *bootPtr = strdup(devicePtr);
2248        break;
2249     }
2250        }
2251    
2252        free(line);
2253        fclose(deviceMap);
2254        return 0;
2255    }
2256    
2257    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2258        char * grubDevice;
2259    
2260        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2261     dbgPrintf("error looking for grub installation device\n");
2262        else
2263     dbgPrintf("grubby installation device: %s\n", grubDevice);
2264    
2265        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2266     dbgPrintf("error looking for grub boot device\n");
2267        else
2268     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2269    
2270        free(grubDevice);
2271        return 0;
2272    }
2273    
2274    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2275        /*
2276         * This SuSE grub configuration file at this location is not your average
2277         * grub configuration file, but instead the grub commands used to setup
2278         * grub on that system.
2279         */
2280        const char * path;
2281        const static char default_path[] = "/etc/grub.conf";
2282    
2283        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2284     path = default_path;
2285    
2286        if (!isSuseGrubConf(path)) return 1;
2287    
2288        if (lbaPtr) {
2289            *lbaPtr = 0;
2290            if (suseGrubConfGetLba(path, lbaPtr))
2291                return 1;
2292        }
2293    
2294        if (bootPtr) {
2295            *bootPtr = NULL;
2296            suseGrubConfGetBoot(path, bootPtr);
2297        }
2298    
2299        return 0;
2300  }  }
2301    
2302  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2306  int parseSysconfigGrub(int * lbaPtr, cha
2306      char * start;      char * start;
2307      char * param;      char * param;
2308    
2309      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2310      if (!in) return 1;      if (!in) return 1;
2311    
2312      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2347  int parseSysconfigGrub(int * lbaPtr, cha
2347  }  }
2348    
2349  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2350      char * boot;      char * boot = NULL;
2351      int lba;      int lba;
2352    
2353      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2354   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2355   if (boot) printf("boot=%s\n", boot);      free(boot);
2356        return;
2357     }
2358        } else {
2359            if (parseSysconfigGrub(&lba, &boot)) {
2360        free(boot);
2361        return;
2362     }
2363        }
2364    
2365        if (lba) printf("lba\n");
2366        if (boot) {
2367     printf("boot=%s\n", boot);
2368     free(boot);
2369      }      }
2370  }  }
2371    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2381  int displayInfo(struct grubConfig * conf
2381   return 1;   return 1;
2382      }      }
2383    
2384      /* 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
2385         be a better way */         be a better way */
2386      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2387   dumpSysconfigGrub();   dumpSysconfigGrub();
2388      } else {      } else {
2389   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2390   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2391      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2392   }   }
2393    
2394   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2395   if (line) printf("lba\n");   if (line) printf("lba\n");
2396      }      }
2397    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2406  int displayInfo(struct grubConfig * conf
2406      return 0;      return 0;
2407  }  }
2408    
2409    struct singleLine * addLineTmpl(struct singleEntry * entry,
2410     struct singleLine * tmplLine,
2411     struct singleLine * prevLine,
2412     const char * val,
2413     struct configFileInfo * cfi)
2414    {
2415        struct singleLine * newLine = lineDup(tmplLine);
2416    
2417        if (val) {
2418     /* override the inherited value with our own.
2419     * This is a little weak because it only applies to elements[1]
2420     */
2421     if (newLine->numElements > 1)
2422        removeElement(newLine, 1);
2423     insertElement(newLine, val, 1, cfi);
2424    
2425     /* but try to keep the rootspec from the template... sigh */
2426     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2427        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2428        if (rootspec != NULL) {
2429     free(newLine->elements[1].item);
2430     newLine->elements[1].item =
2431        sdupprintf("%s%s", rootspec, val);
2432        }
2433     }
2434        }
2435    
2436        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2437          newLine->elements[0].item : "");
2438    
2439        if (!entry->lines) {
2440     /* first one on the list */
2441     entry->lines = newLine;
2442        } else if (prevLine) {
2443     /* add after prevLine */
2444     newLine->next = prevLine->next;
2445     prevLine->next = newLine;
2446        }
2447    
2448        return newLine;
2449    }
2450    
2451  /* val may be NULL */  /* val may be NULL */
2452  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2453       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2454       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2455       char * val) {       const char * val) {
2456      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2457      int i;      struct keywordTypes * kw;
2458        struct singleLine tmpl;
2459    
2460      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2461   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2462      if (type != LT_TITLE || !cfi->titleBracketed)       */
2463          if (!cfi->keywords[i].key) abort();  
2464        if (type == LT_TITLE && cfi->titleBracketed) {
2465     /* we're doing a bracketed title (zipl) */
2466     tmpl.type = type;
2467     tmpl.numElements = 1;
2468     tmpl.elements = alloca(sizeof(*tmpl.elements));
2469     tmpl.elements[0].item = alloca(strlen(val)+3);
2470     sprintf(tmpl.elements[0].item, "[%s]", val);
2471     tmpl.elements[0].indent = "";
2472     val = NULL;
2473        } else if (type == LT_MENUENTRY) {
2474     char *lineend = "--class gnu-linux --class gnu --class os {";
2475     if (!val) {
2476        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2477        abort();
2478     }
2479     kw = getKeywordByType(type, cfi);
2480     if (!kw) {
2481        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2482        abort();
2483     }
2484     tmpl.indent = "";
2485     tmpl.type = type;
2486     tmpl.numElements = 3;
2487     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2488     tmpl.elements[0].item = kw->key;
2489     tmpl.elements[0].indent = alloca(2);
2490     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2491     tmpl.elements[1].item = (char *)val;
2492     tmpl.elements[1].indent = alloca(2);
2493     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2494     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2495     strcpy(tmpl.elements[2].item, lineend);
2496     tmpl.elements[2].indent = "";
2497        } else {
2498     kw = getKeywordByType(type, cfi);
2499     if (!kw) {
2500        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2501        abort();
2502     }
2503     tmpl.type = type;
2504     tmpl.numElements = val ? 2 : 1;
2505     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2506     tmpl.elements[0].item = kw->key;
2507     tmpl.elements[0].indent = alloca(2);
2508     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2509     if (val) {
2510        tmpl.elements[1].item = (char *)val;
2511        tmpl.elements[1].indent = "";
2512     }
2513        }
2514    
2515      /* 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
2516         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2517         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
2518         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2519         differently from the rest) */         differently from the rest) */
2520      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2521   line = entry->lines;   if (line->numElements) prev = line;
2522   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2523   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;  
2524      }      }
2525    
2526      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2527          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2528          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2529          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2530          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2531          line->elements[0].indent = malloc(2);   else
2532          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2533          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2534             if (menuEntry)
2535          if (val) {      tmpl.indent = "\t";
2536              line->elements[1].item = val;   else if (prev == entry->lines)
2537              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2538          }   else
2539      } 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("");  
2540      }      }
2541    
2542      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2543  }  }
2544    
2545  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2564  void removeLine(struct singleEntry * ent
2564      free(line);      free(line);
2565  }  }
2566    
2567    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2568    {
2569        struct singleLine newLine = {
2570     .indent = tmplLine->indent,
2571     .type = tmplLine->type,
2572     .next = tmplLine->next,
2573        };
2574        int firstQuotedItem = -1;
2575        int quoteLen = 0;
2576        int j;
2577        int element = 0;
2578        char *c;
2579    
2580        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2581        strcpy(c, tmplLine->elements[0].item);
2582        insertElement(&newLine, c, element++, cfi);
2583        free(c);
2584        c = NULL;
2585    
2586        for (j = 1; j < tmplLine->numElements; j++) {
2587     if (firstQuotedItem == -1) {
2588        quoteLen += strlen(tmplLine->elements[j].item);
2589        
2590        if (isquote(tmplLine->elements[j].item[0])) {
2591     firstQuotedItem = j;
2592            quoteLen += strlen(tmplLine->elements[j].indent);
2593        } else {
2594     c = malloc(quoteLen + 1);
2595     strcpy(c, tmplLine->elements[j].item);
2596     insertElement(&newLine, c, element++, cfi);
2597     free(c);
2598     quoteLen = 0;
2599        }
2600     } else {
2601        int itemlen = strlen(tmplLine->elements[j].item);
2602        quoteLen += itemlen;
2603        quoteLen += strlen(tmplLine->elements[j].indent);
2604        
2605        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2606     c = malloc(quoteLen + 1);
2607     c[0] = '\0';
2608     for (int i = firstQuotedItem; i < j+1; i++) {
2609        strcat(c, tmplLine->elements[i].item);
2610        strcat(c, tmplLine->elements[i].indent);
2611     }
2612     insertElement(&newLine, c, element++, cfi);
2613     free(c);
2614    
2615     firstQuotedItem = -1;
2616     quoteLen = 0;
2617        }
2618     }
2619        }
2620        while (tmplLine->numElements)
2621     removeElement(tmplLine, 0);
2622        if (tmplLine->elements)
2623     free(tmplLine->elements);
2624    
2625        tmplLine->numElements = newLine.numElements;
2626        tmplLine->elements = newLine.elements;
2627    }
2628    
2629    static void insertElement(struct singleLine * line,
2630      const char * item, int insertHere,
2631      struct configFileInfo * cfi)
2632    {
2633        struct keywordTypes * kw;
2634        char indent[2] = "";
2635    
2636        /* sanity check */
2637        if (insertHere > line->numElements) {
2638     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2639      insertHere, line->numElements);
2640     insertHere = line->numElements;
2641        }
2642    
2643        line->elements = realloc(line->elements, (line->numElements + 1) *
2644         sizeof(*line->elements));
2645        memmove(&line->elements[insertHere+1],
2646        &line->elements[insertHere],
2647        (line->numElements - insertHere) *
2648        sizeof(*line->elements));
2649        line->elements[insertHere].item = strdup(item);
2650    
2651        kw = getKeywordByType(line->type, cfi);
2652    
2653        if (line->numElements == 0) {
2654     indent[0] = '\0';
2655        } else if (insertHere == 0) {
2656     indent[0] = kw->nextChar;
2657        } else if (kw->separatorChar != '\0') {
2658     indent[0] = kw->separatorChar;
2659        } else {
2660     indent[0] = ' ';
2661        }
2662    
2663        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2664     /* move the end-of-line forward */
2665     line->elements[insertHere].indent =
2666        line->elements[insertHere-1].indent;
2667     line->elements[insertHere-1].indent = strdup(indent);
2668        } else {
2669     line->elements[insertHere].indent = strdup(indent);
2670        }
2671    
2672        line->numElements++;
2673    
2674        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2675          line->elements[0].item,
2676          line->elements[insertHere].item,
2677          line->elements[insertHere].indent,
2678          insertHere);
2679    }
2680    
2681    static void removeElement(struct singleLine * line, int removeHere) {
2682        int i;
2683    
2684        /* sanity check */
2685        if (removeHere >= line->numElements) return;
2686    
2687        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2688          removeHere, line->elements[removeHere].item);
2689    
2690        free(line->elements[removeHere].item);
2691    
2692        if (removeHere > 1) {
2693     /* previous argument gets this argument's post-indentation */
2694     free(line->elements[removeHere-1].indent);
2695     line->elements[removeHere-1].indent =
2696        line->elements[removeHere].indent;
2697        } else {
2698     free(line->elements[removeHere].indent);
2699        }
2700    
2701        /* now collapse the array, but don't bother to realloc smaller */
2702        for (i = removeHere; i < line->numElements - 1; i++)
2703     line->elements[i] = line->elements[i + 1];
2704    
2705        line->numElements--;
2706    }
2707    
2708  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2709      char * first, * second;      char * first, * second;
2710      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2727  int updateActualImage(struct grubConfig
2727      struct singleEntry * entry;      struct singleEntry * entry;
2728      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2729      int index = 0;      int index = 0;
2730      int i, j, k;      int i, k;
2731      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2732      const char ** arg;      const char ** arg;
2733      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2734      int firstElement;      int firstElement;
2735      int *usedElements, *usedArgs;      int *usedElements;
2736        int doreplace;
2737    
2738      if (!image) return 0;      if (!image) return 0;
2739    
# Line 1609  int updateActualImage(struct grubConfig Line 2760  int updateActualImage(struct grubConfig
2760   }   }
2761      }      }
2762    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2763    
2764      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2765   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2766    
2767      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2768   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2769    
2770      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2771    
2772      k = 0;   if (multibootArgs && !entry->multiboot)
2773      for (arg = newArgs; *arg; arg++)      continue;
2774          k++;  
2775      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2776     * LT_KERNELARGS, use that.  Otherwise use
2777     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2778     */
2779     if (useKernelArgs) {
2780        line = getLineByType(LT_KERNELARGS, entry->lines);
2781        if (!line) {
2782     /* no LT_KERNELARGS, need to add it */
2783     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2784           cfg->secondaryIndent, NULL);
2785        }
2786        firstElement = 1;
2787    
2788      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2789   index++;      line = getLineByType(LT_HYPER, entry->lines);
2790        if (!line) {
2791     /* a multiboot entry without LT_HYPER? */
2792     continue;
2793        }
2794        firstElement = 2;
2795    
2796   line = entry->lines;   } else {
2797   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2798   if (!line) continue;      if (!line) {
2799   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2800     continue;
2801          if (entry->multiboot && !multibootArgs) {      }
2802              /* 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;  
2803   }   }
2804    
2805   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2806      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2807      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2808     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2809        /* this is a multiboot entry, make sure there's
2810         * -- on the args line
2811         */
2812        for (i = firstElement; i < line->numElements; i++) {
2813     if (!strcmp(line->elements[i].item, "--"))
2814        break;
2815        }
2816        if (i == line->numElements) {
2817     /* assume all existing args are kernel args,
2818     * prepend -- to make it official
2819     */
2820     insertElement(line, "--", firstElement, cfg->cfi);
2821     i = firstElement;
2822        }
2823        if (!multibootArgs) {
2824     /* kernel args start after the -- */
2825     firstElement = i + 1;
2826        }
2827     } else if (cfg->cfi->mbConcatArgs) {
2828        /* this is a non-multiboot entry, remove hyper args */
2829        for (i = firstElement; i < line->numElements; i++) {
2830     if (!strcmp(line->elements[i].item, "--"))
2831        break;
2832        }
2833        if (i < line->numElements) {
2834     /* remove args up to -- */
2835     while (strcmp(line->elements[firstElement].item, "--"))
2836        removeElement(line, firstElement);
2837     /* remove -- */
2838     removeElement(line, firstElement);
2839        }
2840   }   }
2841    
2842          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2843    
2844          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2845   for (arg = newArgs; *arg; arg++) {  
2846              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2847      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2848     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2849        !strcmp(line->elements[i].item, "--"))
2850     {
2851        /* reached the end of hyper args, insert here */
2852        doreplace = 0;
2853        break;  
2854     }
2855                  if (usedElements[i])                  if (usedElements[i])
2856                      continue;                      continue;
2857   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2858                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2859      break;      break;
2860                  }                  }
2861              }              }
     chptr = strchr(*arg, '=');  
2862    
2863      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2864   /* replace */   /* direct replacement */
2865   free(line->elements[i].item);   free(line->elements[i].item);
2866   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("");  
  }  
2867    
2868   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2869   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2870      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2871   /* append */   if (rootLine) {
2872   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2873   (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(" ");  
2874   } else {   } else {
2875      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2876         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2877   }   }
2878        }
2879    
2880   line->numElements++;      else {
2881     /* insert/append */
2882     insertElement(line, *arg, i, cfg->cfi);
2883     usedElements = realloc(usedElements, line->numElements *
2884           sizeof(*usedElements));
2885     memmove(&usedElements[i + 1], &usedElements[i],
2886     line->numElements - i - 1);
2887     usedElements[i] = 1;
2888    
2889   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2890     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2891     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2892   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2893      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2894      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2895   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2896   }   }
2897      }      }
             k++;  
2898   }   }
2899    
2900          free(usedElements);          free(usedElements);
2901    
  /* 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? */  
2902   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2903      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2904   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2905        !strcmp(line->elements[i].item, "--"))
2906        /* reached the end of hyper args, stop here */
2907        break;
2908     if (!argMatch(line->elements[i].item, *arg)) {
2909        removeElement(line, i);
2910      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;  
2911   }   }
2912        }
2913   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2914        if (useRoot && !strncmp(*arg, "root=", 5)) {
2915   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2916      line->elements[j - 1] = line->elements[j];   if (rootLine)
2917        removeLine(entry, rootLine);
  line->numElements--;  
2918      }      }
2919   }   }
2920    
# Line 1760  int updateActualImage(struct grubConfig Line 2925  int updateActualImage(struct grubConfig
2925   }   }
2926      }      }
2927    
     free(usedArgs);  
2928      free(newArgs);      free(newArgs);
2929      free(oldArgs);      free(oldArgs);
2930    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2950  int updateImage(struct grubConfig * cfg,
2950      return rc;      return rc;
2951  }  }
2952    
2953    int updateInitrd(struct grubConfig * cfg, const char * image,
2954                     const char * prefix, const char * initrd) {
2955        struct singleEntry * entry;
2956        struct singleLine * line, * kernelLine, *endLine = NULL;
2957        int index = 0;
2958    
2959        if (!image) return 0;
2960    
2961        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2962            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2963            if (!kernelLine) continue;
2964    
2965            line = getLineByType(LT_INITRD, entry->lines);
2966            if (line)
2967                removeLine(entry, line);
2968            if (prefix) {
2969                int prefixLen = strlen(prefix);
2970                if (!strncmp(initrd, prefix, prefixLen))
2971                    initrd += prefixLen;
2972            }
2973     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2974     if (endLine)
2975        removeLine(entry, endLine);
2976            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2977            if (!line)
2978        return 1;
2979     if (endLine) {
2980        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2981                if (!line)
2982     return 1;
2983     }
2984    
2985            break;
2986        }
2987    
2988        return 0;
2989    }
2990    
2991  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2992      int fd;      int fd;
2993      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3011  int checkDeviceBootloader(const char * d
3011      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3012   return 0;   return 0;
3013    
3014      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3015   offset = boot[2] + 2;   offset = boot[2] + 2;
3016      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3017   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3018      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3019   offset = boot[1] + 2;        offset = boot[1] + 2;
3020            /*
3021     * it looks like grub, when copying stage1 into the mbr, patches stage1
3022     * right after the JMP location, replacing other instructions such as
3023     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3024     * different bytes.
3025     */
3026          if ((bootSect[offset + 1] == NOOP_OPCODE)
3027      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3028     offset = offset + 3;
3029          }
3030      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3031   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3032      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3168  int checkForLilo(struct grubConfig * con
3168      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3169  }  }
3170    
3171    int checkForGrub2(struct grubConfig * config) {
3172        if (!access("/etc/grub.d/", R_OK))
3173     return 2;
3174    
3175        return 1;
3176    }
3177    
3178  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3179      int fd;      int fd;
3180      unsigned char bootSect[512];      unsigned char bootSect[512];
3181      char * boot;      char * boot;
3182        int onSuse = isSuseSystem();
3183    
3184      if (parseSysconfigGrub(NULL, &boot))  
3185   return 0;      if (onSuse) {
3186     if (parseSuseGrubConf(NULL, &boot))
3187        return 0;
3188        } else {
3189     if (parseSysconfigGrub(NULL, &boot))
3190        return 0;
3191        }
3192    
3193      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3194      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3202  int checkForGrub(struct grubConfig * con
3202      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3203   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3204   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3205     close(fd);
3206     return 1;
3207        }
3208        close(fd);
3209    
3210        /* The more elaborate checks do not work on SuSE. The checks done
3211         * seem to be reasonble (at least for now), so just return success
3212         */
3213        if (onSuse)
3214     return 2;
3215    
3216        return checkDeviceBootloader(boot, bootSect);
3217    }
3218    
3219    int checkForExtLinux(struct grubConfig * config) {
3220        int fd;
3221        unsigned char bootSect[512];
3222        char * boot;
3223        char executable[] = "/boot/extlinux/extlinux";
3224    
3225        printf("entered: checkForExtLinux()\n");
3226    
3227        if (parseSysconfigGrub(NULL, &boot))
3228     return 0;
3229    
3230        /* assume grub is not installed -- not an error condition */
3231        if (!boot)
3232     return 0;
3233    
3234        fd = open(executable, O_RDONLY);
3235        if (fd < 0)
3236     /* this doesn't exist if grub hasn't been installed */
3237     return 0;
3238    
3239        if (read(fd, bootSect, 512) != 512) {
3240     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3241     executable, strerror(errno));
3242   return 1;   return 1;
3243      }      }
3244      close(fd);      close(fd);
# Line 1983  int checkForGrub(struct grubConfig * con Line 3246  int checkForGrub(struct grubConfig * con
3246      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3247  }  }
3248    
3249    int checkForYaboot(struct grubConfig * config) {
3250        /*
3251         * This is a simplistic check that we consider good enough for own puporses
3252         *
3253         * If we were to properly check if yaboot is *installed* we'd need to:
3254         * 1) get the system boot device (LT_BOOT)
3255         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3256         *    the content on the boot device
3257         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3258         * 4) check again if binary and boot device contents match
3259         */
3260        if (!access("/etc/yaboot.conf", R_OK))
3261     return 2;
3262    
3263        return 1;
3264    }
3265    
3266    int checkForElilo(struct grubConfig * config) {
3267        if (!access("/etc/elilo.conf", R_OK))
3268     return 2;
3269    
3270        return 1;
3271    }
3272    
3273  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3274      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3275    
# Line 1994  static char * getRootSpecifier(char * st Line 3281  static char * getRootSpecifier(char * st
3281      return rootspec;      return rootspec;
3282  }  }
3283    
3284    static char * getInitrdVal(struct grubConfig * config,
3285       const char * prefix, struct singleLine *tmplLine,
3286       const char * newKernelInitrd,
3287       const char ** extraInitrds, int extraInitrdCount)
3288    {
3289        char *initrdVal, *end;
3290        int i;
3291        size_t totalSize;
3292        size_t prefixLen;
3293        char separatorChar;
3294    
3295        prefixLen = strlen(prefix);
3296        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3297    
3298        for (i = 0; i < extraInitrdCount; i++) {
3299     totalSize += sizeof(separatorChar);
3300     totalSize += strlen(extraInitrds[i]) - prefixLen;
3301        }
3302    
3303        initrdVal = end = malloc(totalSize);
3304    
3305        end = stpcpy (end, newKernelInitrd + prefixLen);
3306    
3307        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3308        for (i = 0; i < extraInitrdCount; i++) {
3309     const char *extraInitrd;
3310     int j;
3311    
3312     extraInitrd = extraInitrds[i] + prefixLen;
3313     /* Don't add entries that are already there */
3314     if (tmplLine != NULL) {
3315        for (j = 2; j < tmplLine->numElements; j++)
3316     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3317        break;
3318    
3319        if (j != tmplLine->numElements)
3320     continue;
3321     }
3322    
3323     *end++ = separatorChar;
3324     end = stpcpy(end, extraInitrd);
3325        }
3326    
3327        return initrdVal;
3328    }
3329    
3330  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3331           const char * prefix,           const char * prefix,
3332   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3333   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3334                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3335                     const char * newMBKernel, const char * newMBKernelArgs) {
3336      struct singleEntry * new;      struct singleEntry * new;
3337      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3338      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3339      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3340    
3341      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3342    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3366  int addNewKernel(struct grubConfig * con
3366      config->entries = new;      config->entries = new;
3367    
3368      /* copy/update from the template */      /* copy/update from the template */
3369      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3370        if (newKernelInitrd)
3371     needs |= NEED_INITRD;
3372      if (newMBKernel) {      if (newMBKernel) {
3373          needs |= KERNEL_MB;          needs |= NEED_MB;
3374          new->multiboot = 1;          new->multiboot = 1;
3375      }      }
3376    
3377      if (template) {      if (template) {
3378   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3379      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3380      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3381   indent = tmplLine->indent;   {
3382        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3383    
3384      /* skip comments */      /* skip comments */
3385      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3386      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3387      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3388    
3389      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3390      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3391     if (!template->multiboot && (needs & NEED_MB)) {
3392              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3393                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3394                  struct singleLine *l;       * hypervisor at the same time.
3395                  needs &= ~ KERNEL_MB;       */
3396        if (config->cfi->mbHyperFirst) {
3397                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3398                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3399                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3400                      newMBKernel + strlen(prefix));
3401                  tmplLine = lastLine;   /* set up for adding the kernel line */
3402                  if (!new->lines) {   free(tmplLine->indent);
3403                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3404                  } else {   needs &= ~NEED_MB;
3405                      newLine->next = l;      }
3406                      newLine = l;      if (needs & NEED_KERNEL) {
3407                  }   /* use addLineTmpl to preserve line elements,
3408                  continue;   * otherwise we could just call addLine.  Unfortunately
3409              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3410                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3411                  continue; /* don't need multiboot kernel here */   * change below.
3412              }   */
3413     struct keywordTypes * mbm_kw =
3414        getKeywordByType(LT_MBMODULE, config->cfi);
3415     if (mbm_kw) {
3416        tmplLine->type = LT_MBMODULE;
3417        free(tmplLine->elements[0].item);
3418        tmplLine->elements[0].item = strdup(mbm_kw->key);
3419     }
3420     newLine = addLineTmpl(new, tmplLine, newLine,
3421          newKernelPath + strlen(prefix), config->cfi);
3422     needs &= ~NEED_KERNEL;
3423        }
3424        if (needs & NEED_MB) { /* !mbHyperFirst */
3425     newLine = addLine(new, config->cfi, LT_HYPER,
3426      config->secondaryIndent,
3427      newMBKernel + strlen(prefix));
3428     needs &= ~NEED_MB;
3429        }
3430     } else if (needs & NEED_KERNEL) {
3431        newLine = addLineTmpl(new, tmplLine, newLine,
3432      newKernelPath + strlen(prefix), config->cfi);
3433        needs &= ~NEED_KERNEL;
3434     }
3435    
3436      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3437   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3438   new->lines = newLine;   if (needs & NEED_MB) {
3439      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3440   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3441   newLine = newLine->next;      needs &= ~NEED_MB;
3442      }   }
3443    
3444        } else if (tmplLine->type == LT_MBMODULE &&
3445           tmplLine->numElements >= 2) {
3446     if (new->multiboot) {
3447        if (needs & NEED_KERNEL) {
3448     newLine = addLineTmpl(new, tmplLine, newLine,
3449          newKernelPath +
3450          strlen(prefix), config->cfi);
3451     needs &= ~NEED_KERNEL;
3452        } else if (config->cfi->mbInitRdIsModule &&
3453           (needs & NEED_INITRD)) {
3454     char *initrdVal;
3455     initrdVal = getInitrdVal(config, prefix, tmplLine,
3456     newKernelInitrd, extraInitrds,
3457     extraInitrdCount);
3458     newLine = addLineTmpl(new, tmplLine, newLine,
3459          initrdVal, config->cfi);
3460     free(initrdVal);
3461     needs &= ~NEED_INITRD;
3462        }
3463     } else if (needs & NEED_KERNEL) {
3464        /* template is multi but new is not,
3465         * insert the kernel in the first module slot
3466         */
3467        tmplLine->type = LT_KERNEL;
3468        free(tmplLine->elements[0].item);
3469        tmplLine->elements[0].item =
3470     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3471        newLine = addLineTmpl(new, tmplLine, newLine,
3472      newKernelPath + strlen(prefix), config->cfi);
3473        needs &= ~NEED_KERNEL;
3474     } else if (needs & NEED_INITRD) {
3475        char *initrdVal;
3476        /* template is multi but new is not,
3477         * insert the initrd in the second module slot
3478         */
3479        tmplLine->type = LT_INITRD;
3480        free(tmplLine->elements[0].item);
3481        tmplLine->elements[0].item =
3482     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3483        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3484        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3485        free(initrdVal);
3486        needs &= ~NEED_INITRD;
3487     }
3488    
     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));  
                 }  
3489      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3490      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3491   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3492   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3493                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3494                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3495                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3496                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3497                  }       */
3498                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3499                  if (rootspec != NULL) {   char *initrdVal;
3500                      newLine->elements[1].item = sdupprintf("%s%s",  
3501                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3502                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3503                                                             strlen(prefix));    config->secondaryIndent,
3504                  } else {    initrdVal);
3505                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3506                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3507                  }      }
3508              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3509                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3510   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3511                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3512                      free(newLine->elements[0].item);      free(initrdVal);
3513                      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);  
3514   }   }
3515    
3516   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3517   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3518   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3519     char *nkt = malloc(strlen(newKernelTitle)+3);
3520     strcpy(nkt, "'");
3521     strcat(nkt, newKernelTitle);
3522     strcat(nkt, "'");
3523     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3524     free(nkt);
3525     needs &= ~NEED_TITLE;
3526      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3527                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3528                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3529                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3530                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3531                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3532                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3533                                             newLine->numElements);     config->cfi->titleBracketed) {
3534        /* addLineTmpl doesn't handle titleBracketed */
3535                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3536                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3537                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3538                  newLine->numElements = 1;   }
3539              }      } else if (tmplLine->type == LT_ECHO) {
3540        requote(tmplLine, config->cfi);
3541        static const char *prefix = "'Loading ";
3542        if (tmplLine->numElements > 1 &&
3543        strstr(tmplLine->elements[1].item, prefix) &&
3544        masterLine->next && masterLine->next->type == LT_KERNEL) {
3545     char *newTitle = malloc(strlen(prefix) +
3546     strlen(newKernelTitle) + 2);
3547    
3548     strcpy(newTitle, prefix);
3549     strcat(newTitle, newKernelTitle);
3550     strcat(newTitle, "'");
3551     newLine = addLine(new, config->cfi, LT_ECHO,
3552     tmplLine->indent, newTitle);
3553     free(newTitle);
3554        } else {
3555     /* pass through other lines from the template */
3556     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3557     config->cfi);
3558        }
3559        } else {
3560     /* pass through other lines from the template */
3561     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3562        }
3563   }   }
3564    
3565      } else {      } else {
3566   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3567      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3568     */
3569     switch (config->cfi->entryStart) {
3570        case LT_KERNEL:
3571     if (new->multiboot && config->cfi->mbHyperFirst) {
3572        /* fall through to LT_HYPER */
3573     } else {
3574        newLine = addLine(new, config->cfi, LT_KERNEL,
3575          config->primaryIndent,
3576          newKernelPath + strlen(prefix));
3577        needs &= ~NEED_KERNEL;
3578        break;
3579     }
3580    
3581        case LT_HYPER:
3582     newLine = addLine(new, config->cfi, LT_HYPER,
3583      config->primaryIndent,
3584      newMBKernel + strlen(prefix));
3585     needs &= ~NEED_MB;
3586   break;   break;
         }  
3587    
3588   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3589      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3590       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3591       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3592      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3593       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3594      default:        config->primaryIndent, nkt);
3595                  /* zipl strikes again */   free(nkt);
3596                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3597                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3598                      chptr = newKernelTitle;   break;
3599                      type = LT_TITLE;      }
3600                      break;      case LT_TITLE:
3601                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3602                      abort();   char * templabel;
3603                  }   int x = 0, y = 0;
3604   }  
3605     templabel = strdup(newKernelTitle);
3606     while( templabel[x]){
3607     if( templabel[x] == ' ' ){
3608     y = x;
3609     while( templabel[y] ){
3610     templabel[y] = templabel[y+1];
3611     y++;
3612     }
3613     }
3614     x++;
3615     }
3616     newLine = addLine(new, config->cfi, LT_TITLE,
3617      config->primaryIndent, templabel);
3618     free(templabel);
3619     }else{
3620     newLine = addLine(new, config->cfi, LT_TITLE,
3621      config->primaryIndent, newKernelTitle);
3622     }
3623     needs &= ~NEED_TITLE;
3624     break;
3625    
3626   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3627   new->lines = newLine;   abort();
3628     }
3629      }      }
3630    
3631      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3632          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3633              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3634                                config->secondaryIndent,       */
3635                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3636          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3637              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3638                                config->secondaryIndent,    newKernelTitle);
3639                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3640          /* don't need to check for title as it's guaranteed to have been      }
3641           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3642           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3643          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3644              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3645                                config->secondaryIndent,   needs &= ~NEED_MB;
3646                                newKernelInitrd + strlen(prefix));      }
3647      } else {      if (needs & NEED_KERNEL) {
3648          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3649              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3650                                config->secondaryIndent,        config->cfi)) ?
3651                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3652          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3653              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3654                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3655                                newKernelTitle);      }
3656          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3657              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3658                                config->secondaryIndent,    config->secondaryIndent,
3659                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3660     needs &= ~NEED_MB;
3661        }
3662        if (needs & NEED_INITRD) {
3663     char *initrdVal;
3664     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3665     newLine = addLine(new, config->cfi,
3666      (new->multiboot && getKeywordByType(LT_MBMODULE,
3667          config->cfi)) ?
3668      LT_MBMODULE : LT_INITRD,
3669      config->secondaryIndent,
3670      initrdVal);
3671     free(initrdVal);
3672     needs &= ~NEED_INITRD;
3673        }
3674        if (needs & NEED_END) {
3675     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3676     config->secondaryIndent, NULL);
3677     needs &= ~NEED_END;
3678        }
3679    
3680        if (needs) {
3681     printf(_("grubby: needs=%d, aborting\n"), needs);
3682     abort();
3683      }      }
3684    
3685      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3688  int addNewKernel(struct grubConfig * con
3688      return 0;      return 0;
3689  }  }
3690    
3691    static void traceback(int signum)
3692    {
3693        void *array[40];
3694        size_t size;
3695    
3696        signal(SIGSEGV, SIG_DFL);
3697        memset(array, '\0', sizeof (array));
3698        size = backtrace(array, 40);
3699    
3700        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3701                (unsigned long)size);
3702        backtrace_symbols_fd(array, size, STDERR_FILENO);
3703        exit(1);
3704    }
3705    
3706  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3707      poptContext optCon;      poptContext optCon;
3708      char * grubConfig = NULL;      const char * grubConfig = NULL;
3709      char * outputFile = NULL;      char * outputFile = NULL;
3710      int arg = 0;      int arg = 0;
3711      int flags = 0;      int flags = 0;
3712      int badImageOkay = 0;      int badImageOkay = 0;
3713        int configureGrub2 = 0;
3714      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3715      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3716        int configureExtLinux = 0;
3717      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3718        int extraInitrdCount = 0;
3719      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3720      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3721      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3731  int main(int argc, const char ** argv) {
3731      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3732      char * removeArgs = NULL;      char * removeArgs = NULL;
3733      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3734        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3735      const char * chptr = NULL;      const char * chptr = NULL;
3736      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3737      struct grubConfig * config;      struct grubConfig * config;
3738      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3739      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3740      int displayDefault = 0;      int displayDefault = 0;
3741        int displayDefaultIndex = 0;
3742        int displayDefaultTitle = 0;
3743      struct poptOption options[] = {      struct poptOption options[] = {
3744   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3745      _("add an entry for the specified kernel"), _("kernel-path") },      _("add an entry for the specified kernel"), _("kernel-path") },
# Line 2322  int main(int argc, const char ** argv) { Line 3757  int main(int argc, const char ** argv) {
3757   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3758      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3759      _("bootfs") },      _("bootfs") },
3760  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3761   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3762      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3763  #endif  #endif
3764   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3765      _("path to grub config file to update (\"-\" for stdin)"),      _("path to grub config file to update (\"-\" for stdin)"),
# Line 2335  int main(int argc, const char ** argv) { Line 3770  int main(int argc, const char ** argv) {
3770        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3771        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3772        "template"), NULL },        "template"), NULL },
3773     { "debug", 0, 0, &debug, 0,
3774        _("print debugging information for failures") },
3775   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3776      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3777     { "default-index", 0, 0, &displayDefaultIndex, 0,
3778        _("display the index of the default kernel") },
3779     { "default-title", 0, 0, &displayDefaultTitle, 0,
3780        _("display the title of the default kernel") },
3781   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3782      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3783     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3784        _("configure extlinux bootloader (from syslinux)") },
3785   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3786      _("configure grub bootloader") },      _("configure grub bootloader") },
3787     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3788        _("configure grub2 bootloader") },
3789   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3790      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3791      _("kernel-path") },      _("kernel-path") },
3792   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3793      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3794     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3795        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3796   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3797      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3798   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3829  int main(int argc, const char ** argv) {
3829   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3830      };      };
3831    
3832        useextlinuxmenu=0;
3833    
3834        signal(SIGSEGV, traceback);
3835    
3836      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3837      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3838    
# Line 2391  int main(int argc, const char ** argv) { Line 3842  int main(int argc, const char ** argv) {
3842      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3843      exit(0);      exit(0);
3844      break;      break;
3845      case 'i':
3846        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3847         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3848        } else {
3849     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3850     return 1;
3851        }
3852        break;
3853   }   }
3854      }      }
3855    
# Line 2406  int main(int argc, const char ** argv) { Line 3865  int main(int argc, const char ** argv) {
3865   return 1;   return 1;
3866      }      }
3867    
3868      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3869   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3870     configureExtLinux ) > 1) {
3871   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3872   return 1;   return 1;
3873      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3874   fprintf(stderr,   fprintf(stderr,
3875      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3876   return 1;   return 1;
3877        } else if (configureGrub2) {
3878     cfi = &grub2ConfigType;
3879      } else if (configureLilo) {      } else if (configureLilo) {
3880   cfi = &liloConfigType;   cfi = &liloConfigType;
3881      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3888  int main(int argc, const char ** argv) {
3888          cfi = &siloConfigType;          cfi = &siloConfigType;
3889      } else if (configureZipl) {      } else if (configureZipl) {
3890          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3891        } else if (configureExtLinux) {
3892     cfi = &extlinuxConfigType;
3893     useextlinuxmenu=1;
3894      }      }
3895    
3896      if (!cfi) {      if (!cfi) {
3897            if (grub2FindConfig(&grub2ConfigType))
3898        cfi = &grub2ConfigType;
3899     else
3900        #ifdef __ia64__        #ifdef __ia64__
3901   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3902        #elif __powerpc__        #elif __powerpc__
3903   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3904        #elif __sparc__        #elif __sparc__
3905          cfi = &siloConfigType;              cfi = &siloConfigType;
3906        #elif __s390__        #elif __s390__
3907          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3908        #elif __s390x__        #elif __s390x__
3909          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3910        #else        #else
3911   cfi = &grubConfigType;      cfi = &grubConfigType;
3912        #endif        #endif
3913      }      }
3914    
3915      if (!grubConfig)      if (!grubConfig) {
3916   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3917        grubConfig = cfi->findConfig(cfi);
3918     if (!grubConfig)
3919        grubConfig = cfi->defaultConfig;
3920        }
3921    
3922      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3923    newKernelPath || removeKernelPath || makeDefault ||    newKernelPath || removeKernelPath || makeDefault ||
3924    defaultKernel)) {    defaultKernel || displayDefaultIndex || displayDefaultTitle)) {
3925   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3926    "specified option"));    "specified option"));
3927   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3937  int main(int argc, const char ** argv) {
3937      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3938   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3939   return 1;   return 1;
3940      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3941    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3942    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3943   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3944   return 1;   return 1;
3945      }      }
# Line 2492  int main(int argc, const char ** argv) { Line 3964  int main(int argc, const char ** argv) {
3964   defaultKernel = NULL;   defaultKernel = NULL;
3965      }      }
3966    
3967      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3968   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3969   "is used\n"));   "is used\n"));
3970   return 1;   return 1;
# Line 2500  int main(int argc, const char ** argv) { Line 3972  int main(int argc, const char ** argv) {
3972    
3973      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3974   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3975          && !removeMBKernel) {          && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle) {
3976   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3977   return 1;   return 1;
3978      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 3992  int main(int argc, const char ** argv) {
3992   bootPrefix = "";   bootPrefix = "";
3993      }      }
3994    
3995        if (!cfi->mbAllowExtraInitRds &&
3996     extraInitrdCount > 0) {
3997     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
3998     return 1;
3999        }
4000    
4001      if (bootloaderProbe) {      if (bootloaderProbe) {
4002   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4003   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4004    
4005     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4006     if (grub2config) {
4007        gconfig = readConfig(grub2config, &grub2ConfigType);
4008        if (!gconfig)
4009     gr2c = 1;
4010        else
4011     gr2c = checkForGrub2(gconfig);
4012     }
4013    
4014   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4015      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4016        gconfig = readConfig(grubconfig, &grubConfigType);
4017      if (!gconfig)      if (!gconfig)
4018   grc = 1;   grc = 1;
4019      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4028  int main(int argc, const char ** argv) {
4028   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4029   }   }
4030    
4031   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4032        econfig = readConfig(eliloConfigType.defaultConfig,
4033     &eliloConfigType);
4034        if (!econfig)
4035     erc = 1;
4036        else
4037     erc = checkForElilo(econfig);
4038     }
4039    
4040     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4041        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4042        if (!lconfig)
4043     extrc = 1;
4044        else
4045     extrc = checkForExtLinux(lconfig);
4046     }
4047    
4048    
4049     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4050        yconfig = readConfig(yabootConfigType.defaultConfig,
4051     &yabootConfigType);
4052        if (!yconfig)
4053     yrc = 1;
4054        else
4055          yrc = checkForYaboot(lconfig);
4056     }
4057    
4058     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4059        erc == 1)
4060        return 1;
4061    
4062   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4063     if (gr2c == 2) printf("grub2\n");
4064   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4065     if (extrc == 2) printf("extlinux\n");
4066     if (yrc == 2) printf("yaboot\n");
4067     if (erc == 2) printf("elilo\n");
4068    
4069   return 0;   return 0;
4070      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4082  int main(int argc, const char ** argv) {
4082   if (!entry) return 0;   if (!entry) return 0;
4083   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4084    
4085   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4086   if (!line) return 0;   if (!line) return 0;
4087    
4088          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4090  int main(int argc, const char ** argv) {
4090                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4091    
4092   return 0;   return 0;
4093    
4094        } else if (displayDefaultTitle) {
4095     struct singleLine * line;
4096     struct singleEntry * entry;
4097    
4098     if (config->defaultImage == -1) return 0;
4099     entry = findEntryByIndex(config, config->defaultImage);
4100     if (!entry) return 0;
4101    
4102     if (!configureGrub2) {
4103      line = getLineByType(LT_TITLE, entry->lines);
4104      if (!line) return 0;
4105      printf("%s\n", line->elements[1].item);
4106    
4107     } else {
4108      char * title;
4109    
4110      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4111      line = getLineByType(LT_MENUENTRY, entry->lines);
4112      if (!line) return 0;
4113      title = grub2ExtractTitle(line);
4114      if (title)
4115        printf("%s\n", title);
4116     }
4117     return 0;
4118    
4119        } else if (displayDefaultIndex) {
4120            if (config->defaultImage == -1) return 0;
4121            printf("%i\n", config->defaultImage);
4122    
4123      } else if (kernelInfo)      } else if (kernelInfo)
4124   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4125    
# Line 2585  int main(int argc, const char ** argv) { Line 4135  int main(int argc, const char ** argv) {
4135      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4136      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4137                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4138        if (updateKernelPath && newKernelInitrd) {
4139                if (updateInitrd(config, updateKernelPath, bootPrefix,
4140                                 newKernelInitrd)) return 1;
4141        }
4142      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4143                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4144                         (const char **)extraInitrds, extraInitrdCount,
4145                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4146            
4147    
# Line 2597  int main(int argc, const char ** argv) { Line 4152  int main(int argc, const char ** argv) {
4152      }      }
4153    
4154      if (!outputFile)      if (!outputFile)
4155   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4156    
4157      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4158  }  }

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