Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 1868 by niro, Mon Jul 2 13:22:30 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("/");      char *dir = strdupa(outName);
1314                rc = chdir(dirname(dir));
1315        free(dir);
1316      do {      do {
1317   buf = alloca(len + 1);   buf = alloca(len + 1);
1318   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1319   if (rc == len) len += 256;   if (rc == len) len += 256;
1320      } while (rc == len);      } while (rc == len);
1321            
# Line 843  static int writeConfig(struct grubConfig Line 1350  static int writeConfig(struct grubConfig
1350      }      }
1351    
1352      line = cfg->theLines;      line = cfg->theLines;
1353        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1354      while (line) {      while (line) {
1355   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1356     line->numElements == 3 &&
1357     !strcmp(line->elements[1].item, defaultKw->key)) {
1358        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1359        needs &= ~MAIN_DEFAULT;
1360     } else if (line->type == LT_DEFAULT) {
1361      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1362      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1363   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1425  static int numEntries(struct grubConfig
1425      return i;      return i;
1426  }  }
1427    
1428    static char *findDiskForRoot()
1429    {
1430        int fd;
1431        char buf[65536];
1432        char *devname;
1433        char *chptr;
1434        int rc;
1435    
1436        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1437            fprintf(stderr, "grubby: failed to open %s: %s\n",
1438                    _PATH_MOUNTED, strerror(errno));
1439            return NULL;
1440        }
1441    
1442        rc = read(fd, buf, sizeof(buf) - 1);
1443        if (rc <= 0) {
1444            fprintf(stderr, "grubby: failed to read %s: %s\n",
1445                    _PATH_MOUNTED, strerror(errno));
1446            close(fd);
1447            return NULL;
1448        }
1449        close(fd);
1450        buf[rc] = '\0';
1451        chptr = buf;
1452    
1453        char *foundanswer = NULL;
1454    
1455        while (chptr && chptr != buf+rc) {
1456            devname = chptr;
1457    
1458            /*
1459             * The first column of a mtab entry is the device, but if the entry is a
1460             * special device it won't start with /, so move on to the next line.
1461             */
1462            if (*devname != '/') {
1463                chptr = strchr(chptr, '\n');
1464                if (chptr)
1465                    chptr++;
1466                continue;
1467            }
1468    
1469            /* Seek to the next space */
1470            chptr = strchr(chptr, ' ');
1471            if (!chptr) {
1472                fprintf(stderr, "grubby: error parsing %s: %s\n",
1473                        _PATH_MOUNTED, strerror(errno));
1474                return NULL;
1475            }
1476    
1477            /*
1478             * The second column of a mtab entry is the mount point, we are looking
1479             * for '/' obviously.
1480             */
1481            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1482                /* remember the last / entry in mtab */
1483               foundanswer = devname;
1484            }
1485    
1486            /* Next line */
1487            chptr = strchr(chptr, '\n');
1488            if (chptr)
1489                chptr++;
1490        }
1491    
1492        /* Return the last / entry found */
1493        if (foundanswer) {
1494            chptr = strchr(foundanswer, ' ');
1495            *chptr = '\0';
1496            return strdup(foundanswer);
1497        }
1498    
1499        return NULL;
1500    }
1501    
1502    void printEntry(struct singleEntry * entry) {
1503        int i;
1504        struct singleLine * line;
1505    
1506        for (line = entry->lines; line; line = line->next) {
1507     fprintf(stderr, "DBG: %s", line->indent);
1508     for (i = 0; i < line->numElements; i++) {
1509        /* Need to handle this, because we strip the quotes from
1510         * menuentry when read it. */
1511        if (line->type == LT_MENUENTRY && i == 1) {
1512     if(!isquote(*line->elements[i].item))
1513        fprintf(stderr, "\'%s\'", line->elements[i].item);
1514     else
1515        fprintf(stderr, "%s", line->elements[i].item);
1516     fprintf(stderr, "%s", line->elements[i].indent);
1517    
1518     continue;
1519        }
1520        
1521        fprintf(stderr, "%s%s",
1522        line->elements[i].item, line->elements[i].indent);
1523     }
1524     fprintf(stderr, "\n");
1525        }
1526    }
1527    
1528    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1529    {
1530        va_list argp;
1531    
1532        if (!debug)
1533     return;
1534    
1535        va_start(argp, fmt);
1536        fprintf(stderr, "DBG: Image entry failed: ");
1537        vfprintf(stderr, fmt, argp);
1538        printEntry(entry);
1539        va_end(argp);
1540    }
1541    
1542    #define beginswith(s, c) ((s) && (s)[0] == (c))
1543    
1544    static int endswith(const char *s, char c)
1545    {
1546     int slen;
1547    
1548     if (!s || !s[0])
1549     return 0;
1550     slen = strlen(s) - 1;
1551    
1552     return s[slen] == c;
1553    }
1554    
1555  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1556    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1557      struct singleLine * line;      struct singleLine * line;
1558      char * fullName;      char * fullName;
1559      int i;      int i;
     struct stat sb, sb2;  
1560      char * dev;      char * dev;
     char * end;  
1561      char * rootspec;      char * rootspec;
1562        char * rootdev;
1563    
1564      line = entry->lines;      if (skipRemoved && entry->skip) {
1565      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1566         return 0;
1567      if (!line) return 0;      }
1568      if (skipRemoved && entry->skip) return 0;  
1569      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1570        if (!line) {
1571     notSuitablePrintf(entry, "no line found\n");
1572     return 0;
1573        }
1574        if (line->numElements < 2) {
1575     notSuitablePrintf(entry, "line has only %d elements\n",
1576        line->numElements);
1577     return 0;
1578        }
1579    
1580      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1581    
1582      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1583        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1584      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1585      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1586              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1587                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1588      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1589                line->elements[1].item + rootspec_offset);
1590        if (access(fullName, R_OK)) {
1591     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1592     return 0;
1593        }
1594      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1595   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1596      if (i < line->numElements) {      if (i < line->numElements) {
1597   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1598      } else {      } else {
1599   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1600   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1601    
1602   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1603      dev = line->elements[1].item;      dev = line->elements[1].item;
1604   } else {   } else {
1605              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1606      /* 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.
1607      line = entry->lines;       */
1608        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1609    
1610              /* failed to find one */              /* failed to find one */
1611              if (!line) return 0;              if (!line) {
1612     notSuitablePrintf(entry, "no line found\n");
1613     return 0;
1614                }
1615    
1616      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1617          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1618      if (i < line->numElements)      if (i < line->numElements)
1619          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1620      else {      else {
1621     notSuitablePrintf(entry, "no root= entry found\n");
1622   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1623          return 0;          return 0;
1624              }              }
1625   }   }
1626      }      }
1627    
1628      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1629   dev += 6;      if (!getpathbyspec(dev)) {
1630            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1631   /* check which device has this label */          return 0;
1632   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1633   if (!dev) return 0;   dev = getpathbyspec(dev);
1634    
1635        rootdev = findDiskForRoot();
1636        if (!rootdev) {
1637            notSuitablePrintf(entry, "can't find root device\n");
1638     return 0;
1639      }      }
1640    
1641      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1642   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1643      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1644      } else {          free(rootdev);
1645   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1646   if (*end) return 0;      }
1647    
1648        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1649            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1650     getuuidbydev(rootdev), getuuidbydev(dev));
1651     free(rootdev);
1652            return 0;
1653      }      }
     stat("/", &sb2);  
1654    
1655      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1656    
1657      return 1;      return 1;
1658  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1696  struct singleEntry * findEntryByPath(str
1696   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1697   if (!entry) return NULL;   if (!entry) return NULL;
1698    
1699   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1700   if (!line) return NULL;   if (!line) return NULL;
1701    
1702   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1734  struct singleEntry * findEntryByPath(str
1734    
1735   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1736      prefix = "";      prefix = "";
1737      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1738      kernel += 6;      kernel += 6;
1739   }   }
1740    
1741   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1742      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
   
1743    
1744      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;  
                 }  
             }  
1745    
1746      i++;      /* check all the lines matching checkType */
1747        for (line = entry->lines; line; line = line->next) {
1748     line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1749         LT_KERNEL|LT_MBMODULE|LT_HYPER :
1750         checkType, line);
1751     if (!line) break;  /* not found in this entry */
1752    
1753     if (line && line->type != LT_MENUENTRY &&
1754     line->numElements >= 2) {
1755        rootspec = getRootSpecifier(line->elements[1].item);
1756        if (!strcmp(line->elements[1].item +
1757     ((rootspec != NULL) ? strlen(rootspec) : 0),
1758     kernel + strlen(prefix)))
1759     break;
1760     }
1761     if(line->type == LT_MENUENTRY &&
1762     !strcmp(line->elements[1].item, kernel))
1763        break;
1764        }
1765    
1766        /* make sure this entry has a kernel identifier; this skips
1767         * non-Linux boot entries (could find netbsd etc, though, which is
1768         * unfortunate)
1769         */
1770        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1771     break; /* found 'im! */
1772   }   }
1773    
1774   if (index) *index = i;   if (index) *index = i;
1775      }      }
1776    
     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);  
     }  
   
1777      return entry;      return entry;
1778  }  }
1779    
# Line 1200  void markRemovedImage(struct grubConfig Line 1852  void markRemovedImage(struct grubConfig
1852        const char * prefix) {        const char * prefix) {
1853      struct singleEntry * entry;      struct singleEntry * entry;
1854    
1855      if (!image) return;      if (!image)
1856     return;
1857    
1858        /* check and see if we're removing the default image */
1859        if (isdigit(*image)) {
1860     entry = findEntryByPath(cfg, image, prefix, NULL);
1861     if(entry)
1862        entry->skip = 1;
1863     return;
1864        }
1865    
1866      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1867   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1869  void markRemovedImage(struct grubConfig
1869    
1870  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1871       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1872       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1873      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1874      int i, j;      int i, j;
1875    
1876      if (newIsDefault) {      if (newIsDefault) {
1877   config->defaultImage = 0;   config->defaultImage = 0;
1878   return;   return;
1879        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1880     if (findEntryByIndex(config, index))
1881        config->defaultImage = index;
1882     else
1883        config->defaultImage = -1;
1884     return;
1885      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1886   i = 0;   i = 0;
1887   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1894  void setDefaultImage(struct grubConfig *
1894    
1895      /* 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
1896         changes */         changes */
1897      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1898     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1899        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1900        return;        return;
1901    
# Line 1286  void displayEntry(struct singleEntry * e Line 1954  void displayEntry(struct singleEntry * e
1954      char * root = NULL;      char * root = NULL;
1955      int i;      int i;
1956    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1957      printf("index=%d\n", index);      printf("index=%d\n", index);
1958    
1959      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1960        if (!line) {
1961            printf("non linux entry\n");
1962            return;
1963        }
1964    
1965        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
1966     printf("kernel=%s\n", line->elements[1].item);
1967        else
1968     printf("kernel=%s%s\n", prefix, line->elements[1].item);
1969    
1970      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1971   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1982  void displayEntry(struct singleEntry * e
1982   }   }
1983   printf("\"\n");   printf("\"\n");
1984      } else {      } else {
1985   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1986   if (line) {   if (line) {
1987      char * s;      char * s;
1988    
# Line 1334  void displayEntry(struct singleEntry * e Line 2006  void displayEntry(struct singleEntry * e
2006      }      }
2007    
2008      if (!root) {      if (!root) {
2009   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2010   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2011      root=line->elements[1].item;      root=line->elements[1].item;
2012      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2021  void displayEntry(struct singleEntry * e
2021   printf("root=%s\n", s);   printf("root=%s\n", s);
2022      }      }
2023    
2024      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2025    
2026      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2027   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2028        printf("initrd=");
2029     else
2030        printf("initrd=%s", prefix);
2031    
2032   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2033      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2034   printf("\n");   printf("\n");
2035      }      }
2036    
2037        line = getLineByType(LT_TITLE, entry->lines);
2038        if (line) {
2039     printf("title=%s\n", line->elements[1].item);
2040        } else {
2041     char * title;
2042     line = getLineByType(LT_MENUENTRY, entry->lines);
2043     title = grub2ExtractTitle(line);
2044     if (title)
2045        printf("title=%s\n", title);
2046        }
2047    }
2048    
2049    int isSuseSystem(void) {
2050        const char * path;
2051        const static char default_path[] = "/etc/SuSE-release";
2052    
2053        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2054     path = default_path;
2055    
2056        if (!access(path, R_OK))
2057     return 1;
2058        return 0;
2059    }
2060    
2061    int isSuseGrubConf(const char * path) {
2062        FILE * grubConf;
2063        char * line = NULL;
2064        size_t len = 0, res = 0;
2065    
2066        grubConf = fopen(path, "r");
2067        if (!grubConf) {
2068            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2069     return 0;
2070        }
2071    
2072        while ((res = getline(&line, &len, grubConf)) != -1) {
2073     if (!strncmp(line, "setup", 5)) {
2074        fclose(grubConf);
2075        free(line);
2076        return 1;
2077     }
2078        }
2079    
2080        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2081          path);
2082    
2083        fclose(grubConf);
2084        free(line);
2085        return 0;
2086    }
2087    
2088    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2089        FILE * grubConf;
2090        char * line = NULL;
2091        size_t res = 0, len = 0;
2092    
2093        if (!path) return 1;
2094        if (!lbaPtr) return 1;
2095    
2096        grubConf = fopen(path, "r");
2097        if (!grubConf) return 1;
2098    
2099        while ((res = getline(&line, &len, grubConf)) != -1) {
2100     if (line[res - 1] == '\n')
2101        line[res - 1] = '\0';
2102     else if (len > res)
2103        line[res] = '\0';
2104     else {
2105        line = realloc(line, res + 1);
2106        line[res] = '\0';
2107     }
2108    
2109     if (!strncmp(line, "setup", 5)) {
2110        if (strstr(line, "--force-lba")) {
2111            *lbaPtr = 1;
2112        } else {
2113            *lbaPtr = 0;
2114        }
2115        dbgPrintf("lba: %i\n", *lbaPtr);
2116        break;
2117     }
2118        }
2119    
2120        free(line);
2121        fclose(grubConf);
2122        return 0;
2123    }
2124    
2125    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2126        FILE * grubConf;
2127        char * line = NULL;
2128        size_t res = 0, len = 0;
2129        char * lastParamPtr = NULL;
2130        char * secLastParamPtr = NULL;
2131        char installDeviceNumber = '\0';
2132        char * bounds = NULL;
2133    
2134        if (!path) return 1;
2135        if (!devicePtr) return 1;
2136    
2137        grubConf = fopen(path, "r");
2138        if (!grubConf) return 1;
2139    
2140        while ((res = getline(&line, &len, grubConf)) != -1) {
2141     if (strncmp(line, "setup", 5))
2142        continue;
2143    
2144     if (line[res - 1] == '\n')
2145        line[res - 1] = '\0';
2146     else if (len > res)
2147        line[res] = '\0';
2148     else {
2149        line = realloc(line, res + 1);
2150        line[res] = '\0';
2151     }
2152    
2153     lastParamPtr = bounds = line + res;
2154    
2155     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2156     while (!isspace(*lastParamPtr))
2157        lastParamPtr--;
2158     lastParamPtr++;
2159    
2160     secLastParamPtr = lastParamPtr - 2;
2161     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2162    
2163     if (lastParamPtr + 3 > bounds) {
2164        dbgPrintf("lastParamPtr going over boundary");
2165        fclose(grubConf);
2166        free(line);
2167        return 1;
2168     }
2169     if (!strncmp(lastParamPtr, "(hd", 3))
2170        lastParamPtr += 3;
2171     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2172    
2173     /*
2174     * Second last parameter will decide wether last parameter is
2175     * an IMAGE_DEVICE or INSTALL_DEVICE
2176     */
2177     while (!isspace(*secLastParamPtr))
2178        secLastParamPtr--;
2179     secLastParamPtr++;
2180    
2181     if (secLastParamPtr + 3 > bounds) {
2182        dbgPrintf("secLastParamPtr going over boundary");
2183        fclose(grubConf);
2184        free(line);
2185        return 1;
2186     }
2187     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2188     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2189        secLastParamPtr += 3;
2190        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2191        installDeviceNumber = *secLastParamPtr;
2192     } else {
2193        installDeviceNumber = *lastParamPtr;
2194     }
2195    
2196     *devicePtr = malloc(6);
2197     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2198     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2199     fclose(grubConf);
2200     free(line);
2201     return 0;
2202        }
2203    
2204        free(line);
2205        fclose(grubConf);
2206        return 1;
2207    }
2208    
2209    int grubGetBootFromDeviceMap(const char * device,
2210         char ** bootPtr) {
2211        FILE * deviceMap;
2212        char * line = NULL;
2213        size_t res = 0, len = 0;
2214        char * devicePtr;
2215        char * bounds = NULL;
2216        const char * path;
2217        const static char default_path[] = "/boot/grub/device.map";
2218    
2219        if (!device) return 1;
2220        if (!bootPtr) return 1;
2221    
2222        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2223     path = default_path;
2224    
2225        dbgPrintf("opening grub device.map file from: %s\n", path);
2226        deviceMap = fopen(path, "r");
2227        if (!deviceMap)
2228     return 1;
2229    
2230        while ((res = getline(&line, &len, deviceMap)) != -1) {
2231            if (!strncmp(line, "#", 1))
2232        continue;
2233    
2234     if (line[res - 1] == '\n')
2235        line[res - 1] = '\0';
2236     else if (len > res)
2237        line[res] = '\0';
2238     else {
2239        line = realloc(line, res + 1);
2240        line[res] = '\0';
2241     }
2242    
2243     devicePtr = line;
2244     bounds = line + res;
2245    
2246     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2247        devicePtr++;
2248     dbgPrintf("device: %s\n", devicePtr);
2249    
2250     if (!strncmp(devicePtr, device, strlen(device))) {
2251        devicePtr += strlen(device);
2252        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2253            devicePtr++;
2254    
2255        *bootPtr = strdup(devicePtr);
2256        break;
2257     }
2258        }
2259    
2260        free(line);
2261        fclose(deviceMap);
2262        return 0;
2263    }
2264    
2265    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2266        char * grubDevice;
2267    
2268        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2269     dbgPrintf("error looking for grub installation device\n");
2270        else
2271     dbgPrintf("grubby installation device: %s\n", grubDevice);
2272    
2273        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2274     dbgPrintf("error looking for grub boot device\n");
2275        else
2276     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2277    
2278        free(grubDevice);
2279        return 0;
2280    }
2281    
2282    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2283        /*
2284         * This SuSE grub configuration file at this location is not your average
2285         * grub configuration file, but instead the grub commands used to setup
2286         * grub on that system.
2287         */
2288        const char * path;
2289        const static char default_path[] = "/etc/grub.conf";
2290    
2291        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2292     path = default_path;
2293    
2294        if (!isSuseGrubConf(path)) return 1;
2295    
2296        if (lbaPtr) {
2297            *lbaPtr = 0;
2298            if (suseGrubConfGetLba(path, lbaPtr))
2299                return 1;
2300        }
2301    
2302        if (bootPtr) {
2303            *bootPtr = NULL;
2304            suseGrubConfGetBoot(path, bootPtr);
2305        }
2306    
2307        return 0;
2308  }  }
2309    
2310  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2314  int parseSysconfigGrub(int * lbaPtr, cha
2314      char * start;      char * start;
2315      char * param;      char * param;
2316    
2317      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2318      if (!in) return 1;      if (!in) return 1;
2319    
2320      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2355  int parseSysconfigGrub(int * lbaPtr, cha
2355  }  }
2356    
2357  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2358      char * boot;      char * boot = NULL;
2359      int lba;      int lba;
2360    
2361      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2362   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2363   if (boot) printf("boot=%s\n", boot);      free(boot);
2364        return;
2365     }
2366        } else {
2367            if (parseSysconfigGrub(&lba, &boot)) {
2368        free(boot);
2369        return;
2370     }
2371        }
2372    
2373        if (lba) printf("lba\n");
2374        if (boot) {
2375     printf("boot=%s\n", boot);
2376     free(boot);
2377      }      }
2378  }  }
2379    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2389  int displayInfo(struct grubConfig * conf
2389   return 1;   return 1;
2390      }      }
2391    
2392      /* 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
2393         be a better way */         be a better way */
2394      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2395   dumpSysconfigGrub();   dumpSysconfigGrub();
2396      } else {      } else {
2397   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2398   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2399      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2400   }   }
2401    
2402   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2403   if (line) printf("lba\n");   if (line) printf("lba\n");
2404      }      }
2405    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2414  int displayInfo(struct grubConfig * conf
2414      return 0;      return 0;
2415  }  }
2416    
2417    struct singleLine * addLineTmpl(struct singleEntry * entry,
2418     struct singleLine * tmplLine,
2419     struct singleLine * prevLine,
2420     const char * val,
2421     struct configFileInfo * cfi)
2422    {
2423        struct singleLine * newLine = lineDup(tmplLine);
2424    
2425        if (val) {
2426     /* override the inherited value with our own.
2427     * This is a little weak because it only applies to elements[1]
2428     */
2429     if (newLine->numElements > 1)
2430        removeElement(newLine, 1);
2431     insertElement(newLine, val, 1, cfi);
2432    
2433     /* but try to keep the rootspec from the template... sigh */
2434     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2435        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2436        if (rootspec != NULL) {
2437     free(newLine->elements[1].item);
2438     newLine->elements[1].item =
2439        sdupprintf("%s%s", rootspec, val);
2440        }
2441     }
2442        }
2443    
2444        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2445          newLine->elements[0].item : "");
2446    
2447        if (!entry->lines) {
2448     /* first one on the list */
2449     entry->lines = newLine;
2450        } else if (prevLine) {
2451     /* add after prevLine */
2452     newLine->next = prevLine->next;
2453     prevLine->next = newLine;
2454        }
2455    
2456        return newLine;
2457    }
2458    
2459  /* val may be NULL */  /* val may be NULL */
2460  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2461       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2462       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2463       char * val) {       const char * val) {
2464      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2465      int i;      struct keywordTypes * kw;
2466        struct singleLine tmpl;
2467    
2468      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2469   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2470      if (type != LT_TITLE || !cfi->titleBracketed)       */
2471          if (!cfi->keywords[i].key) abort();  
2472        if (type == LT_TITLE && cfi->titleBracketed) {
2473     /* we're doing a bracketed title (zipl) */
2474     tmpl.type = type;
2475     tmpl.numElements = 1;
2476     tmpl.elements = alloca(sizeof(*tmpl.elements));
2477     tmpl.elements[0].item = alloca(strlen(val)+3);
2478     sprintf(tmpl.elements[0].item, "[%s]", val);
2479     tmpl.elements[0].indent = "";
2480     val = NULL;
2481        } else if (type == LT_MENUENTRY) {
2482     char *lineend = "--class gnu-linux --class gnu --class os {";
2483     if (!val) {
2484        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2485        abort();
2486     }
2487     kw = getKeywordByType(type, cfi);
2488     if (!kw) {
2489        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2490        abort();
2491     }
2492     tmpl.indent = "";
2493     tmpl.type = type;
2494     tmpl.numElements = 3;
2495     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2496     tmpl.elements[0].item = kw->key;
2497     tmpl.elements[0].indent = alloca(2);
2498     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2499     tmpl.elements[1].item = (char *)val;
2500     tmpl.elements[1].indent = alloca(2);
2501     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2502     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2503     strcpy(tmpl.elements[2].item, lineend);
2504     tmpl.elements[2].indent = "";
2505        } else {
2506     kw = getKeywordByType(type, cfi);
2507     if (!kw) {
2508        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2509        abort();
2510     }
2511     tmpl.type = type;
2512     tmpl.numElements = val ? 2 : 1;
2513     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2514     tmpl.elements[0].item = kw->key;
2515     tmpl.elements[0].indent = alloca(2);
2516     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2517     if (val) {
2518        tmpl.elements[1].item = (char *)val;
2519        tmpl.elements[1].indent = "";
2520     }
2521        }
2522    
2523      /* 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
2524         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2525         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
2526         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2527         differently from the rest) */         differently from the rest) */
2528      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2529   line = entry->lines;   if (line->numElements) prev = line;
2530   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2531   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;  
2532      }      }
2533    
2534      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2535          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2536          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2537          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2538          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2539          line->elements[0].indent = malloc(2);   else
2540          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2541          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2542             if (menuEntry)
2543          if (val) {      tmpl.indent = "\t";
2544              line->elements[1].item = val;   else if (prev == entry->lines)
2545              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2546          }   else
2547      } 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("");  
2548      }      }
2549    
2550      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2551  }  }
2552    
2553  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2572  void removeLine(struct singleEntry * ent
2572      free(line);      free(line);
2573  }  }
2574    
2575    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2576    {
2577        struct singleLine newLine = {
2578     .indent = tmplLine->indent,
2579     .type = tmplLine->type,
2580     .next = tmplLine->next,
2581        };
2582        int firstQuotedItem = -1;
2583        int quoteLen = 0;
2584        int j;
2585        int element = 0;
2586        char *c;
2587    
2588        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2589        strcpy(c, tmplLine->elements[0].item);
2590        insertElement(&newLine, c, element++, cfi);
2591        free(c);
2592        c = NULL;
2593    
2594        for (j = 1; j < tmplLine->numElements; j++) {
2595     if (firstQuotedItem == -1) {
2596        quoteLen += strlen(tmplLine->elements[j].item);
2597        
2598        if (isquote(tmplLine->elements[j].item[0])) {
2599     firstQuotedItem = j;
2600            quoteLen += strlen(tmplLine->elements[j].indent);
2601        } else {
2602     c = malloc(quoteLen + 1);
2603     strcpy(c, tmplLine->elements[j].item);
2604     insertElement(&newLine, c, element++, cfi);
2605     free(c);
2606     quoteLen = 0;
2607        }
2608     } else {
2609        int itemlen = strlen(tmplLine->elements[j].item);
2610        quoteLen += itemlen;
2611        quoteLen += strlen(tmplLine->elements[j].indent);
2612        
2613        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2614     c = malloc(quoteLen + 1);
2615     c[0] = '\0';
2616     for (int i = firstQuotedItem; i < j+1; i++) {
2617        strcat(c, tmplLine->elements[i].item);
2618        strcat(c, tmplLine->elements[i].indent);
2619     }
2620     insertElement(&newLine, c, element++, cfi);
2621     free(c);
2622    
2623     firstQuotedItem = -1;
2624     quoteLen = 0;
2625        }
2626     }
2627        }
2628        while (tmplLine->numElements)
2629     removeElement(tmplLine, 0);
2630        if (tmplLine->elements)
2631     free(tmplLine->elements);
2632    
2633        tmplLine->numElements = newLine.numElements;
2634        tmplLine->elements = newLine.elements;
2635    }
2636    
2637    static void insertElement(struct singleLine * line,
2638      const char * item, int insertHere,
2639      struct configFileInfo * cfi)
2640    {
2641        struct keywordTypes * kw;
2642        char indent[2] = "";
2643    
2644        /* sanity check */
2645        if (insertHere > line->numElements) {
2646     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2647      insertHere, line->numElements);
2648     insertHere = line->numElements;
2649        }
2650    
2651        line->elements = realloc(line->elements, (line->numElements + 1) *
2652         sizeof(*line->elements));
2653        memmove(&line->elements[insertHere+1],
2654        &line->elements[insertHere],
2655        (line->numElements - insertHere) *
2656        sizeof(*line->elements));
2657        line->elements[insertHere].item = strdup(item);
2658    
2659        kw = getKeywordByType(line->type, cfi);
2660    
2661        if (line->numElements == 0) {
2662     indent[0] = '\0';
2663        } else if (insertHere == 0) {
2664     indent[0] = kw->nextChar;
2665        } else if (kw->separatorChar != '\0') {
2666     indent[0] = kw->separatorChar;
2667        } else {
2668     indent[0] = ' ';
2669        }
2670    
2671        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2672     /* move the end-of-line forward */
2673     line->elements[insertHere].indent =
2674        line->elements[insertHere-1].indent;
2675     line->elements[insertHere-1].indent = strdup(indent);
2676        } else {
2677     line->elements[insertHere].indent = strdup(indent);
2678        }
2679    
2680        line->numElements++;
2681    
2682        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2683          line->elements[0].item,
2684          line->elements[insertHere].item,
2685          line->elements[insertHere].indent,
2686          insertHere);
2687    }
2688    
2689    static void removeElement(struct singleLine * line, int removeHere) {
2690        int i;
2691    
2692        /* sanity check */
2693        if (removeHere >= line->numElements) return;
2694    
2695        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2696          removeHere, line->elements[removeHere].item);
2697    
2698        free(line->elements[removeHere].item);
2699    
2700        if (removeHere > 1) {
2701     /* previous argument gets this argument's post-indentation */
2702     free(line->elements[removeHere-1].indent);
2703     line->elements[removeHere-1].indent =
2704        line->elements[removeHere].indent;
2705        } else {
2706     free(line->elements[removeHere].indent);
2707        }
2708    
2709        /* now collapse the array, but don't bother to realloc smaller */
2710        for (i = removeHere; i < line->numElements - 1; i++)
2711     line->elements[i] = line->elements[i + 1];
2712    
2713        line->numElements--;
2714    }
2715    
2716  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2717      char * first, * second;      char * first, * second;
2718      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2735  int updateActualImage(struct grubConfig
2735      struct singleEntry * entry;      struct singleEntry * entry;
2736      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2737      int index = 0;      int index = 0;
2738      int i, j, k;      int i, k;
2739      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2740      const char ** arg;      const char ** arg;
2741      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2742      int firstElement;      int firstElement;
2743      int *usedElements, *usedArgs;      int *usedElements;
2744        int doreplace;
2745    
2746      if (!image) return 0;      if (!image) return 0;
2747    
# Line 1609  int updateActualImage(struct grubConfig Line 2768  int updateActualImage(struct grubConfig
2768   }   }
2769      }      }
2770    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2771    
2772      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2773   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2774    
2775      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2776   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2777    
2778      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2779    
2780      k = 0;   if (multibootArgs && !entry->multiboot)
2781      for (arg = newArgs; *arg; arg++)      continue;
2782          k++;  
2783      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2784     * LT_KERNELARGS, use that.  Otherwise use
2785     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2786     */
2787     if (useKernelArgs) {
2788        line = getLineByType(LT_KERNELARGS, entry->lines);
2789        if (!line) {
2790     /* no LT_KERNELARGS, need to add it */
2791     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2792           cfg->secondaryIndent, NULL);
2793        }
2794        firstElement = 1;
2795    
2796      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2797   index++;      line = getLineByType(LT_HYPER, entry->lines);
2798        if (!line) {
2799     /* a multiboot entry without LT_HYPER? */
2800     continue;
2801        }
2802        firstElement = 2;
2803    
2804   line = entry->lines;   } else {
2805   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2806   if (!line) continue;      if (!line) {
2807   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2808     continue;
2809          if (entry->multiboot && !multibootArgs) {      }
2810              /* 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;  
2811   }   }
2812    
2813   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2814      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2815      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2816     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2817        /* this is a multiboot entry, make sure there's
2818         * -- on the args line
2819         */
2820        for (i = firstElement; i < line->numElements; i++) {
2821     if (!strcmp(line->elements[i].item, "--"))
2822        break;
2823        }
2824        if (i == line->numElements) {
2825     /* assume all existing args are kernel args,
2826     * prepend -- to make it official
2827     */
2828     insertElement(line, "--", firstElement, cfg->cfi);
2829     i = firstElement;
2830        }
2831        if (!multibootArgs) {
2832     /* kernel args start after the -- */
2833     firstElement = i + 1;
2834        }
2835     } else if (cfg->cfi->mbConcatArgs) {
2836        /* this is a non-multiboot entry, remove hyper args */
2837        for (i = firstElement; i < line->numElements; i++) {
2838     if (!strcmp(line->elements[i].item, "--"))
2839        break;
2840        }
2841        if (i < line->numElements) {
2842     /* remove args up to -- */
2843     while (strcmp(line->elements[firstElement].item, "--"))
2844        removeElement(line, firstElement);
2845     /* remove -- */
2846     removeElement(line, firstElement);
2847        }
2848   }   }
2849    
2850          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2851    
2852          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2853   for (arg = newArgs; *arg; arg++) {  
2854              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2855      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2856     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2857        !strcmp(line->elements[i].item, "--"))
2858     {
2859        /* reached the end of hyper args, insert here */
2860        doreplace = 0;
2861        break;  
2862     }
2863                  if (usedElements[i])                  if (usedElements[i])
2864                      continue;                      continue;
2865   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2866                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2867      break;      break;
2868                  }                  }
2869              }              }
     chptr = strchr(*arg, '=');  
2870    
2871      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2872   /* replace */   /* direct replacement */
2873   free(line->elements[i].item);   free(line->elements[i].item);
2874   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("");  
  }  
2875    
2876   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2877   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2878      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2879   /* append */   if (rootLine) {
2880   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2881   (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(" ");  
2882   } else {   } else {
2883      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2884         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2885   }   }
2886        }
2887    
2888   line->numElements++;      else {
2889     /* insert/append */
2890     insertElement(line, *arg, i, cfg->cfi);
2891     usedElements = realloc(usedElements, line->numElements *
2892           sizeof(*usedElements));
2893     memmove(&usedElements[i + 1], &usedElements[i],
2894     line->numElements - i - 1);
2895     usedElements[i] = 1;
2896    
2897   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2898     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2899     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2900   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2901      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2902      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2903   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2904   }   }
2905      }      }
             k++;  
2906   }   }
2907    
2908          free(usedElements);          free(usedElements);
2909    
  /* 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? */  
2910   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2911      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2912   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2913        !strcmp(line->elements[i].item, "--"))
2914        /* reached the end of hyper args, stop here */
2915        break;
2916     if (!argMatch(line->elements[i].item, *arg)) {
2917        removeElement(line, i);
2918      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;  
2919   }   }
2920        }
2921   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2922        if (useRoot && !strncmp(*arg, "root=", 5)) {
2923   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2924      line->elements[j - 1] = line->elements[j];   if (rootLine)
2925        removeLine(entry, rootLine);
  line->numElements--;  
2926      }      }
2927   }   }
2928    
# Line 1760  int updateActualImage(struct grubConfig Line 2933  int updateActualImage(struct grubConfig
2933   }   }
2934      }      }
2935    
     free(usedArgs);  
2936      free(newArgs);      free(newArgs);
2937      free(oldArgs);      free(oldArgs);
2938    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2958  int updateImage(struct grubConfig * cfg,
2958      return rc;      return rc;
2959  }  }
2960    
2961    int updateInitrd(struct grubConfig * cfg, const char * image,
2962                     const char * prefix, const char * initrd) {
2963        struct singleEntry * entry;
2964        struct singleLine * line, * kernelLine, *endLine = NULL;
2965        int index = 0;
2966    
2967        if (!image) return 0;
2968    
2969        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2970            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2971            if (!kernelLine) continue;
2972    
2973            line = getLineByType(LT_INITRD, entry->lines);
2974            if (line)
2975                removeLine(entry, line);
2976            if (prefix) {
2977                int prefixLen = strlen(prefix);
2978                if (!strncmp(initrd, prefix, prefixLen))
2979                    initrd += prefixLen;
2980            }
2981     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2982     if (endLine)
2983        removeLine(entry, endLine);
2984            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2985            if (!line)
2986        return 1;
2987     if (endLine) {
2988        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2989                if (!line)
2990     return 1;
2991     }
2992    
2993            break;
2994        }
2995    
2996        return 0;
2997    }
2998    
2999  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3000      int fd;      int fd;
3001      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3019  int checkDeviceBootloader(const char * d
3019      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3020   return 0;   return 0;
3021    
3022      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3023   offset = boot[2] + 2;   offset = boot[2] + 2;
3024      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3025   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3026      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3027   offset = boot[1] + 2;        offset = boot[1] + 2;
3028            /*
3029     * it looks like grub, when copying stage1 into the mbr, patches stage1
3030     * right after the JMP location, replacing other instructions such as
3031     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3032     * different bytes.
3033     */
3034          if ((bootSect[offset + 1] == NOOP_OPCODE)
3035      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3036     offset = offset + 3;
3037          }
3038      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3039   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3040      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3176  int checkForLilo(struct grubConfig * con
3176      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3177  }  }
3178    
3179    int checkForGrub2(struct grubConfig * config) {
3180        if (!access("/etc/grub.d/", R_OK))
3181     return 2;
3182    
3183        return 1;
3184    }
3185    
3186  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3187      int fd;      int fd;
3188      unsigned char bootSect[512];      unsigned char bootSect[512];
3189      char * boot;      char * boot;
3190        int onSuse = isSuseSystem();
3191    
3192      if (parseSysconfigGrub(NULL, &boot))  
3193   return 0;      if (onSuse) {
3194     if (parseSuseGrubConf(NULL, &boot))
3195        return 0;
3196        } else {
3197     if (parseSysconfigGrub(NULL, &boot))
3198        return 0;
3199        }
3200    
3201      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3202      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3210  int checkForGrub(struct grubConfig * con
3210      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3211   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3212   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3213     close(fd);
3214   return 1;   return 1;
3215      }      }
3216      close(fd);      close(fd);
3217    
3218        /* The more elaborate checks do not work on SuSE. The checks done
3219         * seem to be reasonble (at least for now), so just return success
3220         */
3221        if (onSuse)
3222     return 2;
3223    
3224      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3225  }  }
3226    
3227    int checkForExtLinux(struct grubConfig * config) {
3228        int fd;
3229        unsigned char bootSect[512];
3230        char * boot;
3231        char executable[] = "/boot/extlinux/extlinux";
3232    
3233        printf("entered: checkForExtLinux()\n");
3234    
3235        if (parseSysconfigGrub(NULL, &boot))
3236     return 0;
3237    
3238        /* assume grub is not installed -- not an error condition */
3239        if (!boot)
3240     return 0;
3241    
3242        fd = open(executable, O_RDONLY);
3243        if (fd < 0)
3244     /* this doesn't exist if grub hasn't been installed */
3245     return 0;
3246    
3247        if (read(fd, bootSect, 512) != 512) {
3248     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3249     executable, strerror(errno));
3250     return 1;
3251        }
3252        close(fd);
3253    
3254        return checkDeviceBootloader(boot, bootSect);
3255    }
3256    
3257    int checkForYaboot(struct grubConfig * config) {
3258        /*
3259         * This is a simplistic check that we consider good enough for own puporses
3260         *
3261         * If we were to properly check if yaboot is *installed* we'd need to:
3262         * 1) get the system boot device (LT_BOOT)
3263         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3264         *    the content on the boot device
3265         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3266         * 4) check again if binary and boot device contents match
3267         */
3268        if (!access("/etc/yaboot.conf", R_OK))
3269     return 2;
3270    
3271        return 1;
3272    }
3273    
3274    int checkForElilo(struct grubConfig * config) {
3275        if (!access("/etc/elilo.conf", R_OK))
3276     return 2;
3277    
3278        return 1;
3279    }
3280    
3281  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3282      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3283    
# Line 1994  static char * getRootSpecifier(char * st Line 3289  static char * getRootSpecifier(char * st
3289      return rootspec;      return rootspec;
3290  }  }
3291    
3292    static char * getInitrdVal(struct grubConfig * config,
3293       const char * prefix, struct singleLine *tmplLine,
3294       const char * newKernelInitrd,
3295       const char ** extraInitrds, int extraInitrdCount)
3296    {
3297        char *initrdVal, *end;
3298        int i;
3299        size_t totalSize;
3300        size_t prefixLen;
3301        char separatorChar;
3302    
3303        prefixLen = strlen(prefix);
3304        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3305    
3306        for (i = 0; i < extraInitrdCount; i++) {
3307     totalSize += sizeof(separatorChar);
3308     totalSize += strlen(extraInitrds[i]) - prefixLen;
3309        }
3310    
3311        initrdVal = end = malloc(totalSize);
3312    
3313        end = stpcpy (end, newKernelInitrd + prefixLen);
3314    
3315        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3316        for (i = 0; i < extraInitrdCount; i++) {
3317     const char *extraInitrd;
3318     int j;
3319    
3320     extraInitrd = extraInitrds[i] + prefixLen;
3321     /* Don't add entries that are already there */
3322     if (tmplLine != NULL) {
3323        for (j = 2; j < tmplLine->numElements; j++)
3324     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3325        break;
3326    
3327        if (j != tmplLine->numElements)
3328     continue;
3329     }
3330    
3331     *end++ = separatorChar;
3332     end = stpcpy(end, extraInitrd);
3333        }
3334    
3335        return initrdVal;
3336    }
3337    
3338  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3339           const char * prefix,           const char * prefix,
3340   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3341   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3342                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3343                     const char * newMBKernel, const char * newMBKernelArgs) {
3344      struct singleEntry * new;      struct singleEntry * new;
3345      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3346      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3347      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3348    
3349      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3350    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3374  int addNewKernel(struct grubConfig * con
3374      config->entries = new;      config->entries = new;
3375    
3376      /* copy/update from the template */      /* copy/update from the template */
3377      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3378        if (newKernelInitrd)
3379     needs |= NEED_INITRD;
3380      if (newMBKernel) {      if (newMBKernel) {
3381          needs |= KERNEL_MB;          needs |= NEED_MB;
3382          new->multiboot = 1;          new->multiboot = 1;
3383      }      }
3384    
3385      if (template) {      if (template) {
3386   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3387      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3388      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3389   indent = tmplLine->indent;   {
3390        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3391    
3392      /* skip comments */      /* skip comments */
3393      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3394      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3395      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3396    
3397      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3398      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3399     if (!template->multiboot && (needs & NEED_MB)) {
3400              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3401                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3402                  struct singleLine *l;       * hypervisor at the same time.
3403                  needs &= ~ KERNEL_MB;       */
3404        if (config->cfi->mbHyperFirst) {
3405                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3406                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3407                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3408                      newMBKernel + strlen(prefix));
3409                  tmplLine = lastLine;   /* set up for adding the kernel line */
3410                  if (!new->lines) {   free(tmplLine->indent);
3411                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3412                  } else {   needs &= ~NEED_MB;
3413                      newLine->next = l;      }
3414                      newLine = l;      if (needs & NEED_KERNEL) {
3415                  }   /* use addLineTmpl to preserve line elements,
3416                  continue;   * otherwise we could just call addLine.  Unfortunately
3417              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3418                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3419                  continue; /* don't need multiboot kernel here */   * change below.
3420              }   */
3421     struct keywordTypes * mbm_kw =
3422        getKeywordByType(LT_MBMODULE, config->cfi);
3423     if (mbm_kw) {
3424        tmplLine->type = LT_MBMODULE;
3425        free(tmplLine->elements[0].item);
3426        tmplLine->elements[0].item = strdup(mbm_kw->key);
3427     }
3428     newLine = addLineTmpl(new, tmplLine, newLine,
3429          newKernelPath + strlen(prefix), config->cfi);
3430     needs &= ~NEED_KERNEL;
3431        }
3432        if (needs & NEED_MB) { /* !mbHyperFirst */
3433     newLine = addLine(new, config->cfi, LT_HYPER,
3434      config->secondaryIndent,
3435      newMBKernel + strlen(prefix));
3436     needs &= ~NEED_MB;
3437        }
3438     } else if (needs & NEED_KERNEL) {
3439        newLine = addLineTmpl(new, tmplLine, newLine,
3440      newKernelPath + strlen(prefix), config->cfi);
3441        needs &= ~NEED_KERNEL;
3442     }
3443    
3444      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3445   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3446   new->lines = newLine;   if (needs & NEED_MB) {
3447      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3448   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3449   newLine = newLine->next;      needs &= ~NEED_MB;
3450      }   }
3451    
3452        } else if (tmplLine->type == LT_MBMODULE &&
3453           tmplLine->numElements >= 2) {
3454     if (new->multiboot) {
3455        if (needs & NEED_KERNEL) {
3456     newLine = addLineTmpl(new, tmplLine, newLine,
3457          newKernelPath +
3458          strlen(prefix), config->cfi);
3459     needs &= ~NEED_KERNEL;
3460        } else if (config->cfi->mbInitRdIsModule &&
3461           (needs & NEED_INITRD)) {
3462     char *initrdVal;
3463     initrdVal = getInitrdVal(config, prefix, tmplLine,
3464     newKernelInitrd, extraInitrds,
3465     extraInitrdCount);
3466     newLine = addLineTmpl(new, tmplLine, newLine,
3467          initrdVal, config->cfi);
3468     free(initrdVal);
3469     needs &= ~NEED_INITRD;
3470        }
3471     } else if (needs & NEED_KERNEL) {
3472        /* template is multi but new is not,
3473         * insert the kernel in the first module slot
3474         */
3475        tmplLine->type = LT_KERNEL;
3476        free(tmplLine->elements[0].item);
3477        tmplLine->elements[0].item =
3478     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3479        newLine = addLineTmpl(new, tmplLine, newLine,
3480      newKernelPath + strlen(prefix), config->cfi);
3481        needs &= ~NEED_KERNEL;
3482     } else if (needs & NEED_INITRD) {
3483        char *initrdVal;
3484        /* template is multi but new is not,
3485         * insert the initrd in the second module slot
3486         */
3487        tmplLine->type = LT_INITRD;
3488        free(tmplLine->elements[0].item);
3489        tmplLine->elements[0].item =
3490     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3491        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3492        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3493        free(initrdVal);
3494        needs &= ~NEED_INITRD;
3495     }
3496    
     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));  
                 }  
3497      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3498      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3499   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3500   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3501                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3502                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3503                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3504                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3505                  }       */
3506                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3507                  if (rootspec != NULL) {   char *initrdVal;
3508                      newLine->elements[1].item = sdupprintf("%s%s",  
3509                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3510                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3511                                                             strlen(prefix));    config->secondaryIndent,
3512                  } else {    initrdVal);
3513                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3514                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3515                  }      }
3516              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3517                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3518   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3519                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3520                      free(newLine->elements[0].item);      free(initrdVal);
3521                      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);  
3522   }   }
3523    
3524   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3525   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3526   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3527     char *nkt = malloc(strlen(newKernelTitle)+3);
3528     strcpy(nkt, "'");
3529     strcat(nkt, newKernelTitle);
3530     strcat(nkt, "'");
3531     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3532     free(nkt);
3533     needs &= ~NEED_TITLE;
3534      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3535                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3536                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3537                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3538                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3539                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3540                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3541                                             newLine->numElements);     config->cfi->titleBracketed) {
3542        /* addLineTmpl doesn't handle titleBracketed */
3543                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3544                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3545                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3546                  newLine->numElements = 1;   }
3547              }      } else if (tmplLine->type == LT_ECHO) {
3548        requote(tmplLine, config->cfi);
3549        static const char *prefix = "'Loading ";
3550        if (tmplLine->numElements > 1 &&
3551        strstr(tmplLine->elements[1].item, prefix) &&
3552        masterLine->next && masterLine->next->type == LT_KERNEL) {
3553     char *newTitle = malloc(strlen(prefix) +
3554     strlen(newKernelTitle) + 2);
3555    
3556     strcpy(newTitle, prefix);
3557     strcat(newTitle, newKernelTitle);
3558     strcat(newTitle, "'");
3559     newLine = addLine(new, config->cfi, LT_ECHO,
3560     tmplLine->indent, newTitle);
3561     free(newTitle);
3562        } else {
3563     /* pass through other lines from the template */
3564     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3565     config->cfi);
3566        }
3567        } else {
3568     /* pass through other lines from the template */
3569     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3570        }
3571   }   }
3572    
3573      } else {      } else {
3574   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3575      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3576     */
3577     switch (config->cfi->entryStart) {
3578        case LT_KERNEL:
3579     if (new->multiboot && config->cfi->mbHyperFirst) {
3580        /* fall through to LT_HYPER */
3581     } else {
3582        newLine = addLine(new, config->cfi, LT_KERNEL,
3583          config->primaryIndent,
3584          newKernelPath + strlen(prefix));
3585        needs &= ~NEED_KERNEL;
3586        break;
3587     }
3588    
3589        case LT_HYPER:
3590     newLine = addLine(new, config->cfi, LT_HYPER,
3591      config->primaryIndent,
3592      newMBKernel + strlen(prefix));
3593     needs &= ~NEED_MB;
3594   break;   break;
         }  
3595    
3596   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3597      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3598       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3599       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3600      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3601       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3602      default:        config->primaryIndent, nkt);
3603                  /* zipl strikes again */   free(nkt);
3604                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3605                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3606                      chptr = newKernelTitle;   break;
3607                      type = LT_TITLE;      }
3608                      break;      case LT_TITLE:
3609                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3610                      abort();   char * templabel;
3611                  }   int x = 0, y = 0;
3612   }  
3613     templabel = strdup(newKernelTitle);
3614     while( templabel[x]){
3615     if( templabel[x] == ' ' ){
3616     y = x;
3617     while( templabel[y] ){
3618     templabel[y] = templabel[y+1];
3619     y++;
3620     }
3621     }
3622     x++;
3623     }
3624     newLine = addLine(new, config->cfi, LT_TITLE,
3625      config->primaryIndent, templabel);
3626     free(templabel);
3627     }else{
3628     newLine = addLine(new, config->cfi, LT_TITLE,
3629      config->primaryIndent, newKernelTitle);
3630     }
3631     needs &= ~NEED_TITLE;
3632     break;
3633    
3634   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3635   new->lines = newLine;   abort();
3636     }
3637      }      }
3638    
3639      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3640          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3641              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3642                                config->secondaryIndent,       */
3643                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3644          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3645              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3646                                config->secondaryIndent,    newKernelTitle);
3647                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3648          /* don't need to check for title as it's guaranteed to have been      }
3649           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3650           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3651          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3652              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3653                                config->secondaryIndent,   needs &= ~NEED_MB;
3654                                newKernelInitrd + strlen(prefix));      }
3655      } else {      if (needs & NEED_KERNEL) {
3656          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3657              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3658                                config->secondaryIndent,        config->cfi)) ?
3659                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3660          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3661              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3662                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3663                                newKernelTitle);      }
3664          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3665              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3666                                config->secondaryIndent,    config->secondaryIndent,
3667                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3668     needs &= ~NEED_MB;
3669        }
3670        if (needs & NEED_INITRD) {
3671     char *initrdVal;
3672     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3673     newLine = addLine(new, config->cfi,
3674      (new->multiboot && getKeywordByType(LT_MBMODULE,
3675          config->cfi)) ?
3676      LT_MBMODULE : LT_INITRD,
3677      config->secondaryIndent,
3678      initrdVal);
3679     free(initrdVal);
3680     needs &= ~NEED_INITRD;
3681        }
3682        if (needs & NEED_END) {
3683     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3684     config->secondaryIndent, NULL);
3685     needs &= ~NEED_END;
3686        }
3687    
3688        if (needs) {
3689     printf(_("grubby: needs=%d, aborting\n"), needs);
3690     abort();
3691      }      }
3692    
3693      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3696  int addNewKernel(struct grubConfig * con
3696      return 0;      return 0;
3697  }  }
3698    
3699    static void traceback(int signum)
3700    {
3701        void *array[40];
3702        size_t size;
3703    
3704        signal(SIGSEGV, SIG_DFL);
3705        memset(array, '\0', sizeof (array));
3706        size = backtrace(array, 40);
3707    
3708        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3709                (unsigned long)size);
3710        backtrace_symbols_fd(array, size, STDERR_FILENO);
3711        exit(1);
3712    }
3713    
3714  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3715      poptContext optCon;      poptContext optCon;
3716      char * grubConfig = NULL;      const char * grubConfig = NULL;
3717      char * outputFile = NULL;      char * outputFile = NULL;
3718      int arg = 0;      int arg = 0;
3719      int flags = 0;      int flags = 0;
3720      int badImageOkay = 0;      int badImageOkay = 0;
3721        int configureGrub2 = 0;
3722      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3723      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3724        int configureExtLinux = 0;
3725      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3726        int extraInitrdCount = 0;
3727      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3728      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3729      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3739  int main(int argc, const char ** argv) {
3739      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3740      char * removeArgs = NULL;      char * removeArgs = NULL;
3741      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3742        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3743      const char * chptr = NULL;      const char * chptr = NULL;
3744      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3745      struct grubConfig * config;      struct grubConfig * config;
3746      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3747      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3748      int displayDefault = 0;      int displayDefault = 0;
3749        int displayDefaultIndex = 0;
3750        int displayDefaultTitle = 0;
3751        int defaultIndex = -1;
3752      struct poptOption options[] = {      struct poptOption options[] = {
3753   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3754      _("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 3766  int main(int argc, const char ** argv) {
3766   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3767      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3768      _("bootfs") },      _("bootfs") },
3769  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3770   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3771      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3772  #endif  #endif
3773   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3774      _("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 3779  int main(int argc, const char ** argv) {
3779        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3780        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3781        "template"), NULL },        "template"), NULL },
3782     { "debug", 0, 0, &debug, 0,
3783        _("print debugging information for failures") },
3784   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3785      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3786     { "default-index", 0, 0, &displayDefaultIndex, 0,
3787        _("display the index of the default kernel") },
3788     { "default-title", 0, 0, &displayDefaultTitle, 0,
3789        _("display the title of the default kernel") },
3790   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3791      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3792     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3793        _("configure extlinux bootloader (from syslinux)") },
3794   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3795      _("configure grub bootloader") },      _("configure grub bootloader") },
3796     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3797        _("configure grub2 bootloader") },
3798   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3799      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3800      _("kernel-path") },      _("kernel-path") },
3801   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3802      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3803     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3804        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3805   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3806      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3807   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3821  int main(int argc, const char ** argv) {
3821   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3822      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3823        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3824     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3825        _("make the given entry index the default entry"),
3826        _("entry-index") },
3827   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3828      _("configure silo bootloader") },      _("configure silo bootloader") },
3829   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3841  int main(int argc, const char ** argv) {
3841   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3842      };      };
3843    
3844        useextlinuxmenu=0;
3845    
3846        signal(SIGSEGV, traceback);
3847    
3848      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3849      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3850    
# Line 2391  int main(int argc, const char ** argv) { Line 3854  int main(int argc, const char ** argv) {
3854      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3855      exit(0);      exit(0);
3856      break;      break;
3857      case 'i':
3858        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3859         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3860        } else {
3861     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3862     return 1;
3863        }
3864        break;
3865   }   }
3866      }      }
3867    
# Line 2406  int main(int argc, const char ** argv) { Line 3877  int main(int argc, const char ** argv) {
3877   return 1;   return 1;
3878      }      }
3879    
3880      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3881   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3882     configureExtLinux ) > 1) {
3883   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3884   return 1;   return 1;
3885      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3886   fprintf(stderr,   fprintf(stderr,
3887      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3888   return 1;   return 1;
3889        } else if (configureGrub2) {
3890     cfi = &grub2ConfigType;
3891      } else if (configureLilo) {      } else if (configureLilo) {
3892   cfi = &liloConfigType;   cfi = &liloConfigType;
3893      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3900  int main(int argc, const char ** argv) {
3900          cfi = &siloConfigType;          cfi = &siloConfigType;
3901      } else if (configureZipl) {      } else if (configureZipl) {
3902          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3903        } else if (configureExtLinux) {
3904     cfi = &extlinuxConfigType;
3905     useextlinuxmenu=1;
3906      }      }
3907    
3908      if (!cfi) {      if (!cfi) {
3909            if (grub2FindConfig(&grub2ConfigType))
3910        cfi = &grub2ConfigType;
3911     else
3912        #ifdef __ia64__        #ifdef __ia64__
3913   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3914        #elif __powerpc__        #elif __powerpc__
3915   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3916        #elif __sparc__        #elif __sparc__
3917          cfi = &siloConfigType;              cfi = &siloConfigType;
3918        #elif __s390__        #elif __s390__
3919          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3920        #elif __s390x__        #elif __s390x__
3921          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3922        #else        #else
3923   cfi = &grubConfigType;      cfi = &grubConfigType;
3924        #endif        #endif
3925      }      }
3926    
3927      if (!grubConfig)      if (!grubConfig) {
3928   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3929        grubConfig = cfi->findConfig(cfi);
3930     if (!grubConfig)
3931        grubConfig = cfi->defaultConfig;
3932        }
3933    
3934      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3935    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
3936    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
3937        (defaultIndex >= 0))) {
3938   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3939    "specified option"));    "specified option"));
3940   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3950  int main(int argc, const char ** argv) {
3950      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3951   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3952   return 1;   return 1;
3953      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3954    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3955    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3956   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3957   return 1;   return 1;
3958      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 3976  int main(int argc, const char ** argv) {
3976   makeDefault = 1;   makeDefault = 1;
3977   defaultKernel = NULL;   defaultKernel = NULL;
3978      }      }
3979        else if (defaultKernel && (defaultIndex >= 0)) {
3980     fprintf(stderr, _("grubby: --set-default and --set-default-index "
3981      "may not be used together\n"));
3982     return 1;
3983        }
3984    
3985      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3986   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3987   "is used\n"));   "is used\n"));
3988   return 1;   return 1;
3989      }      }
3990    
3991      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3992   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3993          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
3994     && (defaultIndex == -1)) {
3995   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3996   return 1;   return 1;
3997      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4011  int main(int argc, const char ** argv) {
4011   bootPrefix = "";   bootPrefix = "";
4012      }      }
4013    
4014        if (!cfi->mbAllowExtraInitRds &&
4015     extraInitrdCount > 0) {
4016     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4017     return 1;
4018        }
4019    
4020      if (bootloaderProbe) {      if (bootloaderProbe) {
4021   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4022   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4023    
4024     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4025     if (grub2config) {
4026        gconfig = readConfig(grub2config, &grub2ConfigType);
4027        if (!gconfig)
4028     gr2c = 1;
4029        else
4030     gr2c = checkForGrub2(gconfig);
4031     }
4032    
4033   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4034      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4035        gconfig = readConfig(grubconfig, &grubConfigType);
4036      if (!gconfig)      if (!gconfig)
4037   grc = 1;   grc = 1;
4038      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4047  int main(int argc, const char ** argv) {
4047   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4048   }   }
4049    
4050   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4051        econfig = readConfig(eliloConfigType.defaultConfig,
4052     &eliloConfigType);
4053        if (!econfig)
4054     erc = 1;
4055        else
4056     erc = checkForElilo(econfig);
4057     }
4058    
4059     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4060        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4061        if (!lconfig)
4062     extrc = 1;
4063        else
4064     extrc = checkForExtLinux(lconfig);
4065     }
4066    
4067    
4068     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4069        yconfig = readConfig(yabootConfigType.defaultConfig,
4070     &yabootConfigType);
4071        if (!yconfig)
4072     yrc = 1;
4073        else
4074     yrc = checkForYaboot(yconfig);
4075     }
4076    
4077     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4078     erc == 1)
4079        return 1;
4080    
4081   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4082     if (gr2c == 2) printf("grub2\n");
4083   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4084     if (extrc == 2) printf("extlinux\n");
4085     if (yrc == 2) printf("yaboot\n");
4086     if (erc == 2) printf("elilo\n");
4087    
4088   return 0;   return 0;
4089      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4101  int main(int argc, const char ** argv) {
4101   if (!entry) return 0;   if (!entry) return 0;
4102   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4103    
4104   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4105   if (!line) return 0;   if (!line) return 0;
4106    
4107          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4109  int main(int argc, const char ** argv) {
4109                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4110    
4111   return 0;   return 0;
4112    
4113        } else if (displayDefaultTitle) {
4114     struct singleLine * line;
4115     struct singleEntry * entry;
4116    
4117     if (config->defaultImage == -1) return 0;
4118     entry = findEntryByIndex(config, config->defaultImage);
4119     if (!entry) return 0;
4120    
4121     if (!configureGrub2) {
4122      line = getLineByType(LT_TITLE, entry->lines);
4123      if (!line) return 0;
4124      printf("%s\n", line->elements[1].item);
4125    
4126     } else {
4127      char * title;
4128    
4129      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4130      line = getLineByType(LT_MENUENTRY, entry->lines);
4131      if (!line) return 0;
4132      title = grub2ExtractTitle(line);
4133      if (title)
4134        printf("%s\n", title);
4135     }
4136     return 0;
4137    
4138        } else if (displayDefaultIndex) {
4139            if (config->defaultImage == -1) return 0;
4140            printf("%i\n", config->defaultImage);
4141    
4142      } else if (kernelInfo)      } else if (kernelInfo)
4143   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4144    
# Line 2581  int main(int argc, const char ** argv) { Line 4150  int main(int argc, const char ** argv) {
4150      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4151      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4152      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4153      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4154      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4155      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4156                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4157        if (updateKernelPath && newKernelInitrd) {
4158                if (updateInitrd(config, updateKernelPath, bootPrefix,
4159                                 newKernelInitrd)) return 1;
4160        }
4161      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4162                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4163                         (const char **)extraInitrds, extraInitrdCount,
4164                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4165            
4166    
# Line 2597  int main(int argc, const char ** argv) { Line 4171  int main(int argc, const char ** argv) {
4171      }      }
4172    
4173      if (!outputFile)      if (!outputFile)
4174   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4175    
4176      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4177  }  }

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