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 1866 by niro, Mon Jul 2 13:21:25 2012 UTC
# Line 1  Line 1 
1  /* Copyright (C) 2001-2005 Red Hat, Inc.  /*
2     * grubby.c
3     This program is free software; you can redistribute it and/or   *
4     modify it under the terms of the General Public License as published   * Copyright (C) 2001-2008 Red Hat, Inc.
5     by the Free Software Foundation; either version 2 of the License, or   * All rights reserved.
6     (at your option) any later version.   *
7     * This program is free software; you can redistribute it and/or modify
8     This program is distributed in the hope that it will be useful,   * it under the terms of the GNU General Public License as published by
9     but WITHOUT ANY WARRANTY; without even the implied warranty of   * the Free Software Foundation; either version 2 of the License, or
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * (at your option) any later version.
11     General Public License for more details.   *
12     * This program is distributed in the hope that it will be useful,
13     You should have received a copy of the GNU General Public   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     License along with this program; if not, write to the Free   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   * GNU General Public License for more details.
16     02111-1307 USA.  */   *
17     * You should have received a copy of the GNU General Public License
18     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19     */
20    
21    #ifndef _GNU_SOURCE
22    #define _GNU_SOURCE
23    #endif
24  #include <ctype.h>  #include <ctype.h>
25  #include <errno.h>  #include <errno.h>
26  #include <fcntl.h>  #include <fcntl.h>
# Line 25  Line 31 
31  #include <string.h>  #include <string.h>
32  #include <sys/stat.h>  #include <sys/stat.h>
33  #include <unistd.h>  #include <unistd.h>
34    #include <libgen.h>
35    #include <execinfo.h>
36    #include <signal.h>
37    #include <blkid/blkid.h>
38    
39    #ifndef DEBUG
40    #define DEBUG 0
41    #endif
42    
43  #include "mount_by_label.h"  #if DEBUG
44    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
45    #else
46    #define dbgPrintf(format, args...)
47    #endif
48    
49    int debug = 0; /* Currently just for template debugging */
50    
51  #define _(A) (A)  #define _(A) (A)
52    
53    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
54  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
55    
56    #define NOOP_OPCODE 0x90
57    #define JMP_SHORT_OPCODE 0xeb
58    
59  /* comments get lumped in with indention */  /* comments get lumped in with indention */
60  struct lineElement {  struct lineElement {
61      char * item;      char * item;
62      char * indent;      char * indent;
63  };  };
64    
65  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
66         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
67         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
68        LT_KERNEL       = 1 << 2,
69        LT_INITRD       = 1 << 3,
70        LT_HYPER        = 1 << 4,
71        LT_DEFAULT      = 1 << 5,
72        LT_MBMODULE     = 1 << 6,
73        LT_ROOT         = 1 << 7,
74        LT_FALLBACK     = 1 << 8,
75        LT_KERNELARGS   = 1 << 9,
76        LT_BOOT         = 1 << 10,
77        LT_BOOTROOT     = 1 << 11,
78        LT_LBA          = 1 << 12,
79        LT_OTHER        = 1 << 13,
80        LT_GENERIC      = 1 << 14,
81        LT_ECHO    = 1 << 16,
82        LT_MENUENTRY    = 1 << 17,
83        LT_ENTRY_END    = 1 << 18,
84        LT_SET_VARIABLE = 1 << 19,
85        LT_UNKNOWN      = 1 << 20,
86    };
87    
88  struct singleLine {  struct singleLine {
89      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 104  struct singleEntry {
104    
105  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */  #define GRUB_CONFIG_NO_DEFAULT    (1 << 0) /* don't write out default=0 */
106    
107  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
108  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
109  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
110  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
111  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
112    #define NEED_MB      (1 << 4)
113    #define NEED_END     (1 << 5)
114    
115  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
116  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
117    #define DEFAULT_SAVED_GRUB2 -3
118    
119  struct keywordTypes {  struct keywordTypes {
120      char * key;      char * key;
121      enum lineType_e type;      enum lineType_e type;
122      char nextChar;      char nextChar;
123  } ;      char separatorChar;
124    };
125    
126    struct configFileInfo;
127    
128    typedef const char *(*findConfigFunc)(struct configFileInfo *);
129    typedef const int (*writeLineFunc)(struct configFileInfo *,
130     struct singleLine *line);
131    
132  struct configFileInfo {  struct configFileInfo {
133      char * defaultConfig;      char * defaultConfig;
134        findConfigFunc findConfig;
135        writeLineFunc writeLine;
136      struct keywordTypes * keywords;      struct keywordTypes * keywords;
137      int defaultIsIndex;      int defaultIsIndex;
138        int defaultIsVariable;
139      int defaultSupportSaved;      int defaultSupportSaved;
140      enum lineType_e entrySeparator;      enum lineType_e entryStart;
141        enum lineType_e entryEnd;
142      int needsBootPrefix;      int needsBootPrefix;
143      int argsInQuotes;      int argsInQuotes;
144      int maxTitleLength;      int maxTitleLength;
145      int titleBracketed;      int titleBracketed;
146        int titlePosition;
147        int mbHyperFirst;
148        int mbInitRdIsModule;
149        int mbConcatArgs;
150        int mbAllowExtraInitRds;
151  };  };
152    
153  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 156  struct keywordTypes grubKeywords[] = {
156      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
157      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
158      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
159      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
160      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
161        { "kernel",     LT_HYPER,       ' ' },
162      { NULL,    0, 0 },      { NULL,    0, 0 },
163  };  };
164    
165    const char *grubFindConfig(struct configFileInfo *cfi) {
166        static const char *configFiles[] = {
167     "/boot/grub/grub.conf",
168     "/boot/grub/menu.lst",
169     "/etc/grub.conf",
170     NULL
171        };
172        static int i = -1;
173    
174        if (i == -1) {
175     for (i = 0; configFiles[i] != NULL; i++) {
176        dbgPrintf("Checking \"%s\": ", configFiles[i]);
177        if (!access(configFiles[i], R_OK)) {
178     dbgPrintf("found\n");
179     return configFiles[i];
180        }
181        dbgPrintf("not found\n");
182     }
183        }
184        return configFiles[i];
185    }
186    
187  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
188      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
189      grubKeywords,    /* keywords */      .keywords = grubKeywords,
190      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
191      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
192      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
193      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
194      0,    /* argsInQuotes */      .mbHyperFirst = 1,
195      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
196      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
197    };
198    
199    struct keywordTypes grub2Keywords[] = {
200        { "menuentry",  LT_MENUENTRY,   ' ' },
201        { "}",          LT_ENTRY_END,   ' ' },
202        { "echo",       LT_ECHO,        ' ' },
203        { "set",        LT_SET_VARIABLE,' ', '=' },
204        { "root",       LT_BOOTROOT,    ' ' },
205        { "default",    LT_DEFAULT,     ' ' },
206        { "fallback",   LT_FALLBACK,    ' ' },
207        { "linux",      LT_KERNEL,      ' ' },
208        { "initrd",     LT_INITRD,      ' ', ' ' },
209        { "module",     LT_MBMODULE,    ' ' },
210        { "kernel",     LT_HYPER,       ' ' },
211        { NULL, 0, 0 },
212    };
213    
214    const char *grub2FindConfig(struct configFileInfo *cfi) {
215        static const char *configFiles[] = {
216     "/boot/grub/grub-efi.cfg",
217     "/boot/grub/grub.cfg",
218     NULL
219        };
220        static int i = -1;
221        static const char *grub_cfg = "/boot/grub/grub.cfg";
222    
223        if (i == -1) {
224     for (i = 0; configFiles[i] != NULL; i++) {
225        dbgPrintf("Checking \"%s\": ", configFiles[i]);
226        if (!access(configFiles[i], R_OK)) {
227     dbgPrintf("found\n");
228     return configFiles[i];
229        }
230     }
231        }
232    
233        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
234         * that isn't in grub1, and if it exists, return the config file path
235         * that they use. */
236        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
237     dbgPrintf("found\n");
238     return grub_cfg;
239        }
240    
241        dbgPrintf("not found\n");
242        return configFiles[i];
243    }
244    
245    int sizeOfSingleLine(struct singleLine * line) {
246      int count = 0;
247    
248      for (int i = 0; i < line->numElements; i++) {
249        int indentSize = 0;
250    
251        count = count + strlen(line->elements[i].item);
252    
253        indentSize = strlen(line->elements[i].indent);
254        if (indentSize > 0)
255          count = count + indentSize;
256        else
257          /* be extra safe and add room for whitespaces */
258          count = count + 1;
259      }
260    
261      /* room for trailing terminator */
262      count = count + 1;
263    
264      return count;
265    }
266    
267    static int isquote(char q)
268    {
269        if (q == '\'' || q == '\"')
270     return 1;
271        return 0;
272    }
273    
274    char *grub2ExtractTitle(struct singleLine * line) {
275        char * current;
276        char * current_indent;
277        int current_len;
278        int current_indent_len;
279        int i;
280    
281        /* bail out if line does not start with menuentry */
282        if (strcmp(line->elements[0].item, "menuentry"))
283          return NULL;
284    
285        i = 1;
286        current = line->elements[i].item;
287        current_len = strlen(current);
288    
289        /* if second word is quoted, strip the quotes and return single word */
290        if (isquote(*current) && isquote(current[current_len - 1])) {
291     char *tmp;
292    
293     tmp = strdup(current);
294     *(tmp + current_len - 1) = '\0';
295     return ++tmp;
296        }
297    
298        /* if no quotes, return second word verbatim */
299        if (!isquote(*current))
300     return current;
301    
302        /* second element start with a quote, so we have to find the element
303         * whose last character is also quote (assuming it's the closing one) */
304        int resultMaxSize;
305        char * result;
306        
307        resultMaxSize = sizeOfSingleLine(line);
308        result = malloc(resultMaxSize);
309        snprintf(result, resultMaxSize, "%s", ++current);
310        
311        i++;
312        for (; i < line->numElements; ++i) {
313     current = line->elements[i].item;
314     current_len = strlen(current);
315     current_indent = line->elements[i].indent;
316     current_indent_len = strlen(current_indent);
317    
318     strncat(result, current_indent, current_indent_len);
319     if (!isquote(current[current_len-1])) {
320        strncat(result, current, current_len);
321     } else {
322        strncat(result, current, current_len - 1);
323        break;
324     }
325        }
326        return result;
327    }
328    
329    struct configFileInfo grub2ConfigType = {
330        .findConfig = grub2FindConfig,
331        .keywords = grub2Keywords,
332        .defaultIsIndex = 1,
333        .defaultSupportSaved = 1,
334        .defaultIsVariable = 1,
335        .entryStart = LT_MENUENTRY,
336        .entryEnd = LT_ENTRY_END,
337        .titlePosition = 1,
338        .needsBootPrefix = 1,
339        .mbHyperFirst = 1,
340        .mbInitRdIsModule = 1,
341        .mbAllowExtraInitRds = 1,
342  };  };
343    
344  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 372  struct keywordTypes yabootKeywords[] = {
372      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
373      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
374      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
375      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
376      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
377      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
378      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 392  struct keywordTypes liloKeywords[] = {
392      { NULL,    0, 0 },      { NULL,    0, 0 },
393  };  };
394    
395    struct keywordTypes eliloKeywords[] = {
396        { "label",    LT_TITLE,    '=' },
397        { "root",    LT_ROOT,    '=' },
398        { "default",    LT_DEFAULT,    '=' },
399        { "image",    LT_KERNEL,    '=' },
400        { "initrd",    LT_INITRD,    '=' },
401        { "append",    LT_KERNELARGS,  '=' },
402        { "vmm",    LT_HYPER,       '=' },
403        { NULL,    0, 0 },
404    };
405    
406  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
407      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
408      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 424  struct keywordTypes ziplKeywords[] = {
424      { NULL,         0, 0 },      { NULL,         0, 0 },
425  };  };
426    
427    struct keywordTypes extlinuxKeywords[] = {
428        { "label",    LT_TITLE,    ' ' },
429        { "root",    LT_ROOT,    ' ' },
430        { "default",    LT_DEFAULT,    ' ' },
431        { "kernel",    LT_KERNEL,    ' ' },
432        { "initrd",    LT_INITRD,      ' ', ',' },
433        { "append",    LT_KERNELARGS,  ' ' },
434        { "prompt",     LT_UNKNOWN,     ' ' },
435        { NULL,    0, 0 },
436    };
437    int useextlinuxmenu;
438  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
439      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
440      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
441      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
442      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
443      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
444      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
445  };  };
446    
447  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
448      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
449      liloKeywords,    /* keywords */      .keywords = liloKeywords,
450      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
451      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
452      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
453  };  };
454    
455  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
456      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
457      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
458      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
459      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
460      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
461      1,    /* needsBootPrefix */      .maxTitleLength = 15,
462      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
463  };  };
464    
465  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
466      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
467      siloKeywords,    /* keywords */      .keywords = siloKeywords,
468      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
469      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
470      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
471      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
472  };  };
473    
474  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
475      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
476      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
477      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
478      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
479      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
480      0,    /* needsBootPrefix */  };
481      1,    /* argsInQuotes */  
482      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
483      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
484        .keywords = extlinuxKeywords,
485        .entryStart = LT_TITLE,
486        .needsBootPrefix = 1,
487        .maxTitleLength = 255,
488        .mbAllowExtraInitRds = 1,
489  };  };
490    
491  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 500  struct grubConfig {
500      struct configFileInfo * cfi;      struct configFileInfo * cfi;
501  };  };
502    
503    blkid_cache blkid;
504    
505  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
506  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
507       const char * path, const char * prefix,       const char * path, const char * prefix,
508       int * index);       int * index);
 static char * strndup(char * from, int len);  
509  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
510  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
511    struct singleLine * lineDup(struct singleLine * line);
512  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
513  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
514       struct configFileInfo * cfi);       struct configFileInfo * cfi);
515  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
516         struct configFileInfo * cfi);         struct configFileInfo * cfi);
517  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
518    static void requote(struct singleLine *line, struct configFileInfo * cfi);
519  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
520      char * to;    const char * item, int insertHere,
521      struct configFileInfo * cfi);
522      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
523      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
524      to[len] = '\0';        struct configFileInfo * cfi);
525    static enum lineType_e getTypeByKeyword(char * keyword,
526      return to;   struct configFileInfo * cfi);
527  }  static struct singleLine * getLineByType(enum lineType_e type,
528     struct singleLine * line);
529    static int checkForExtLinux(struct grubConfig * config);
530    struct singleLine * addLineTmpl(struct singleEntry * entry,
531                                    struct singleLine * tmplLine,
532                                    struct singleLine * prevLine,
533                                    const char * val,
534     struct configFileInfo * cfi);
535    struct singleLine *  addLine(struct singleEntry * entry,
536                                 struct configFileInfo * cfi,
537                                 enum lineType_e type, char * defaultIndent,
538                                 const char * val);
539    
540  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
541  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 570  static char * sdupprintf(const char *for
570      return buf;      return buf;
571  }  }
572    
573    static struct keywordTypes * getKeywordByType(enum lineType_e type,
574          struct configFileInfo * cfi) {
575        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
576     if (kw->type == type)
577        return kw;
578        }
579        return NULL;
580    }
581    
582    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
583        struct keywordTypes *kt = getKeywordByType(type, cfi);
584        if (kt)
585     return kt->key;
586        return "unknown";
587    }
588    
589    static char * getpathbyspec(char *device) {
590        if (!blkid)
591            blkid_get_cache(&blkid, NULL);
592    
593        return blkid_get_devname(blkid, device, NULL);
594    }
595    
596    static char * getuuidbydev(char *device) {
597        if (!blkid)
598     blkid_get_cache(&blkid, NULL);
599    
600        return blkid_get_tag_value(blkid, "UUID", device);
601    }
602    
603    static enum lineType_e getTypeByKeyword(char * keyword,
604     struct configFileInfo * cfi) {
605        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
606     if (!strcmp(keyword, kw->key))
607        return kw->type;
608        }
609        return LT_UNKNOWN;
610    }
611    
612    static struct singleLine * getLineByType(enum lineType_e type,
613     struct singleLine * line) {
614        dbgPrintf("getLineByType(%d): ", type);
615        for (; line; line = line->next) {
616     dbgPrintf("%d:%s ", line->type,
617      line->numElements ? line->elements[0].item : "(empty)");
618     if (line->type & type) break;
619        }
620        dbgPrintf(line ? "\n" : " (failed)\n");
621        return line;
622    }
623    
624  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
625      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
626          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
627          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
628              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 634  static int isBracketedTitle(struct singl
634      return 0;      return 0;
635  }  }
636    
637  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
638                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
639      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
640   return 0;   (cfi->titleBracketed && isBracketedTitle(line));
     if (line->type == cfi->entrySeparator)  
         return 1;  
     if (line->type == LT_OTHER)  
         return 1;  
     if (cfi->titleBracketed && isBracketedTitle(line)) {  
         return 1;  
     }  
     return 0;  
641  }  }
642    
643  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 688  static void lineInit(struct singleLine *
688      line->next = NULL;      line->next = NULL;
689  }  }
690    
691  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
692      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
693    
694        newLine->indent = strdup(line->indent);
695        newLine->next = NULL;
696        newLine->type = line->type;
697        newLine->numElements = line->numElements;
698        newLine->elements = malloc(sizeof(*newLine->elements) *
699           newLine->numElements);
700    
701        for (int i = 0; i < newLine->numElements; i++) {
702     newLine->elements[i].indent = strdup(line->elements[i].indent);
703     newLine->elements[i].item = strdup(line->elements[i].item);
704        }
705    
706        return newLine;
707    }
708    
709    static void lineFree(struct singleLine * line) {
710      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
711    
712      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
713   free(line->elements[i].item);   free(line->elements[i].item);
714   free(line->elements[i].indent);   free(line->elements[i].indent);
715      }      }
# Line 405  static void lineFree(struct singleLine * Line 720  static void lineFree(struct singleLine *
720    
721  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
722       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
723      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
724    
725      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
726     /* Need to handle this, because we strip the quotes from
727     * menuentry when read it. */
728     if (line->type == LT_MENUENTRY && i == 1) {
729        if(!isquote(*line->elements[i].item))
730     fprintf(out, "\'%s\'", line->elements[i].item);
731        else
732     fprintf(out, "%s", line->elements[i].item);
733        fprintf(out, "%s", line->elements[i].indent);
734    
735        continue;
736     }
737    
738   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
739      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
740    
741   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
742   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
743        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
744      }      }
745    
746      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 759  static int getNextLine(char ** bufPtr, s
759      char * chptr;      char * chptr;
760      int elementsAlloced = 0;      int elementsAlloced = 0;
761      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
762      int first = 1;      int first = 1;
     int i;  
763    
764      lineFree(line);      lineFree(line);
765    
# Line 489  static int getNextLine(char ** bufPtr, s Line 813  static int getNextLine(char ** bufPtr, s
813      if (!line->numElements)      if (!line->numElements)
814   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
815      else {      else {
816   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
817      if (!strcmp(line->elements[0].item, keywords[i].key)) break;   if (line->type == LT_UNKNOWN) {
   
  if (keywords[i].key) {  
     line->type = keywords[i].type;  
  } else {  
     line->type = LT_UNKNOWN;  
               
818              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
819               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
820              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 828  static int getNextLine(char ** bufPtr, s
828      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
829   char * fullLine;   char * fullLine;
830   int len;   int len;
  int i;  
831    
832   len = strlen(line->indent);   len = strlen(line->indent);
833   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
834      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
835     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
836    
# Line 522  static int getNextLine(char ** bufPtr, s Line 839  static int getNextLine(char ** bufPtr, s
839   free(line->indent);   free(line->indent);
840   line->indent = fullLine;   line->indent = fullLine;
841    
842   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
843      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
844      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
845      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 849  static int getNextLine(char ** bufPtr, s
849   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
850   line->numElements = 0;   line->numElements = 0;
851      }      }
852     } else {
853     struct keywordTypes *kw;
854    
855     kw = getKeywordByType(line->type, cfi);
856    
857     /* space isn't the only separator, we need to split
858     * elements up more
859     */
860     if (!isspace(kw->separatorChar)) {
861        char indent[2] = "";
862        indent[0] = kw->separatorChar;
863        for (int i = 1; i < line->numElements; i++) {
864     char *p;
865     int numNewElements;
866    
867     numNewElements = 0;
868     p = line->elements[i].item;
869     while (*p != '\0') {
870     if (*p == kw->separatorChar)
871     numNewElements++;
872     p++;
873     }
874     if (line->numElements + numNewElements >= elementsAlloced) {
875     elementsAlloced += numNewElements + 5;
876     line->elements = realloc(line->elements,
877        sizeof(*line->elements) * elementsAlloced);
878     }
879    
880     for (int j = line->numElements; j > i; j--) {
881     line->elements[j + numNewElements] = line->elements[j];
882     }
883     line->numElements += numNewElements;
884    
885     p = line->elements[i].item;
886     while (*p != '\0') {
887    
888     while (*p != kw->separatorChar && *p != '\0') p++;
889     if (*p == '\0') {
890     break;
891     }
892    
893     line->elements[i + 1].indent = line->elements[i].indent;
894     line->elements[i].indent = strdup(indent);
895     *p++ = '\0';
896     i++;
897     line->elements[i].item = strdup(p);
898     }
899        }
900     }
901   }   }
902      }      }
903    
# Line 549  static struct grubConfig * readConfig(co Line 915  static struct grubConfig * readConfig(co
915      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
916      char * end;      char * end;
917      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
918      int i, len;      int len;
919      char * buf;      char * buf;
920    
921      if (!strcmp(inName, "-")) {      if (!strcmp(inName, "-")) {
# Line 595  static struct grubConfig * readConfig(co Line 961  static struct grubConfig * readConfig(co
961      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
962   }   }
963    
964   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
965      sawEntry = 1;      sawEntry = 1;
966      if (!entry) {      if (!entry) {
967   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 977  static struct grubConfig * readConfig(co
977      entry->next = NULL;      entry->next = NULL;
978   }   }
979    
980   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
981        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
982        dbgPrintf("%s", line->indent);
983        for (int i = 0; i < line->numElements; i++)
984     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
985        dbgPrintf("\n");
986        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
987        if (kwType && line->numElements == 3 &&
988        !strcmp(line->elements[1].item, kwType->key)) {
989     dbgPrintf("Line sets default config\n");
990     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
991     defaultLine = line;
992        }
993     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
994      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
995      defaultLine = line;      defaultLine = line;
996    
997            } else if (line->type == LT_KERNEL) {
998        /* if by some freak chance this is multiboot and the "module"
999         * lines came earlier in the template, make sure to use LT_HYPER
1000         * instead of LT_KERNEL now
1001         */
1002        if (entry->multiboot)
1003     line->type = LT_HYPER;
1004    
1005          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1006        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1007         * instead, now that we know this is a multiboot entry.
1008         * This only applies to grub, but that's the only place we
1009         * should find LT_MBMODULE lines anyway.
1010         */
1011        for (struct singleLine *l = entry->lines; l; l = l->next) {
1012     if (l->type == LT_HYPER)
1013        break;
1014     else if (l->type == LT_KERNEL) {
1015        l->type = LT_HYPER;
1016        break;
1017     }
1018        }
1019              entry->multiboot = 1;              entry->multiboot = 1;
1020    
1021     } else if (line->type == LT_HYPER) {
1022        entry->multiboot = 1;
1023    
1024   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1025      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1026      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1027    
1028   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1029      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1030      len = 0;      len = 0;
1031      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1032   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1033   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1034      }      }
1035      buf = malloc(len + 1);      buf = malloc(len + 1);
1036      *buf = '\0';      *buf = '\0';
1037    
1038      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1039   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1040   free(line->elements[i].item);   free(line->elements[i].item);
1041    
# Line 643  static struct grubConfig * readConfig(co Line 1049  static struct grubConfig * readConfig(co
1049      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1050      line->elements[1].item = buf;      line->elements[1].item = buf;
1051      line->numElements = 2;      line->numElements = 2;
1052     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1053        /* let --remove-kernel="TITLE=what" work */
1054        len = 0;
1055        char *extras;
1056        char *title;
1057    
1058        for (int i = 1; i < line->numElements; i++) {
1059     len += strlen(line->elements[i].item);
1060     len += strlen(line->elements[i].indent);
1061        }
1062        buf = malloc(len + 1);
1063        *buf = '\0';
1064    
1065        /* allocate mem for extra flags. */
1066        extras = malloc(len + 1);
1067        *extras = '\0';
1068    
1069        /* get title. */
1070        for (int i = 0; i < line->numElements; i++) {
1071     if (!strcmp(line->elements[i].item, "menuentry"))
1072        continue;
1073     if (isquote(*line->elements[i].item))
1074        title = line->elements[i].item + 1;
1075     else
1076        title = line->elements[i].item;
1077    
1078     len = strlen(title);
1079            if (isquote(title[len-1])) {
1080        strncat(buf, title,len-1);
1081        break;
1082     } else {
1083        strcat(buf, title);
1084        strcat(buf, line->elements[i].indent);
1085     }
1086        }
1087    
1088        /* get extras */
1089        int count = 0;
1090        for (int i = 0; i < line->numElements; i++) {
1091     if (count >= 2) {
1092        strcat(extras, line->elements[i].item);
1093        strcat(extras, line->elements[i].indent);
1094     }
1095    
1096     if (!strcmp(line->elements[i].item, "menuentry"))
1097        continue;
1098    
1099     /* count ' or ", there should be two in menuentry line. */
1100     if (isquote(*line->elements[i].item))
1101        count++;
1102    
1103     len = strlen(line->elements[i].item);
1104    
1105     if (isquote(line->elements[i].item[len -1]))
1106        count++;
1107    
1108     /* ok, we get the final ' or ", others are extras. */
1109                }
1110        line->elements[1].indent =
1111     line->elements[line->numElements - 2].indent;
1112        line->elements[1].item = buf;
1113        line->elements[2].indent =
1114     line->elements[line->numElements - 2].indent;
1115        line->elements[2].item = extras;
1116        line->numElements = 3;
1117   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1118      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1119         on write. This is one of the few (the only?) places that grubby         on write. This is one of the few (the only?) places that grubby
# Line 651  static struct grubConfig * readConfig(co Line 1122  static struct grubConfig * readConfig(co
1122      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1123   int last, len;   int last, len;
1124    
1125   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1126      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1127     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1128    
1129   last = line->numElements - 1;   last = line->numElements - 1;
1130   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1131   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1132      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1133      }      }
   
1134   }   }
1135    
1136   /* If we find a generic config option which should live at the   /* If we find a generic config option which should live at the
# Line 680  static struct grubConfig * readConfig(co Line 1150  static struct grubConfig * readConfig(co
1150   movedLine = 1;   movedLine = 1;
1151   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1152   }   }
1153    
1154   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1155     which was moved, drop it. */     which was moved, drop it. */
1156   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {   if (movedLine && line->type == LT_WHITESPACE && last->type == LT_WHITESPACE) {
# Line 695  static struct grubConfig * readConfig(co Line 1166  static struct grubConfig * readConfig(co
1166   entry->lines = line;   entry->lines = line;
1167      else      else
1168   last->next = line;   last->next = line;
1169        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1170    
1171        /* we could have seen this outside of an entry... if so, we
1172         * ignore it like any other line we don't grok */
1173        if (line->type == LT_ENTRY_END && sawEntry)
1174     sawEntry = 0;
1175   } else {   } else {
1176      if (!cfg->theLines)      if (!cfg->theLines)
1177   cfg->theLines = line;   cfg->theLines = line;
1178      else {      else
1179   last->next = line;   last->next = line;
1180      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1181   }   }
1182    
1183   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1185  static struct grubConfig * readConfig(co
1185    
1186      free(incoming);      free(incoming);
1187    
1188        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1189      if (defaultLine) {      if (defaultLine) {
1190   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1191        cfi->defaultSupportSaved &&
1192        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1193        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1194     } else if (cfi->defaultIsVariable) {
1195        char *value = defaultLine->elements[2].item;
1196        while (*value && (*value == '"' || *value == '\'' ||
1197        *value == ' ' || *value == '\t'))
1198     value++;
1199        cfg->defaultImage = strtol(value, &end, 10);
1200        while (*end && (*end == '"' || *end == '\'' ||
1201        *end == ' ' || *end == '\t'))
1202     end++;
1203        if (*end) cfg->defaultImage = -1;
1204     } else if (cfi->defaultSupportSaved &&
1205   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1206      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1207   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1208      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1209      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1210   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1211      i = 0;      int i = 0;
1212      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1213   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1214      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1222  static struct grubConfig * readConfig(co
1222                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1223                  }                  }
1224   i++;   i++;
1225     entry = NULL;
1226      }      }
1227    
1228      if (entry) cfg->defaultImage = i;      if (entry){
1229            cfg->defaultImage = i;
1230        }else{
1231            cfg->defaultImage = -1;
1232        }
1233   }   }
1234        } else {
1235            cfg->defaultImage = 0;
1236      }      }
1237    
1238      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1248  static void writeDefault(FILE * out, cha
1248    
1249      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1250   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1251        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1252     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1253      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1254   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1255      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1256      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1257     cfg->defaultImage);
1258        } else {
1259     fprintf(out, "%sdefault%s%d\n", indent, separator,
1260     cfg->defaultImage);
1261        }
1262   } else {   } else {
1263      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1264    
# Line 769  static void writeDefault(FILE * out, cha Line 1275  static void writeDefault(FILE * out, cha
1275    
1276      if (!entry) return;      if (!entry) return;
1277    
1278      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1279    
1280      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1281   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1309  static int writeConfig(struct grubConfig
1309      int rc;      int rc;
1310    
1311      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1312         directory to / */         directory to the dir of the symlink */
1313      rc = chdir("/");              rc = chdir(dirname(strdupa(outName)));
1314      do {      do {
1315   buf = alloca(len + 1);   buf = alloca(len + 1);
1316   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1317   if (rc == len) len += 256;   if (rc == len) len += 256;
1318      } while (rc == len);      } while (rc == len);
1319            
# Line 843  static int writeConfig(struct grubConfig Line 1348  static int writeConfig(struct grubConfig
1348      }      }
1349    
1350      line = cfg->theLines;      line = cfg->theLines;
1351        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1352      while (line) {      while (line) {
1353   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1354     line->numElements == 3 &&
1355     !strcmp(line->elements[1].item, defaultKw->key)) {
1356        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1357        needs &= ~MAIN_DEFAULT;
1358     } else if (line->type == LT_DEFAULT) {
1359      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1360      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1361   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1423  static int numEntries(struct grubConfig
1423      return i;      return i;
1424  }  }
1425    
1426    static char *findDiskForRoot()
1427    {
1428        int fd;
1429        char buf[65536];
1430        char *devname;
1431        char *chptr;
1432        int rc;
1433    
1434        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1435            fprintf(stderr, "grubby: failed to open %s: %s\n",
1436                    _PATH_MOUNTED, strerror(errno));
1437            return NULL;
1438        }
1439    
1440        rc = read(fd, buf, sizeof(buf) - 1);
1441        if (rc <= 0) {
1442            fprintf(stderr, "grubby: failed to read %s: %s\n",
1443                    _PATH_MOUNTED, strerror(errno));
1444            close(fd);
1445            return NULL;
1446        }
1447        close(fd);
1448        buf[rc] = '\0';
1449        chptr = buf;
1450    
1451        char *foundanswer = NULL;
1452    
1453        while (chptr && chptr != buf+rc) {
1454            devname = chptr;
1455    
1456            /*
1457             * The first column of a mtab entry is the device, but if the entry is a
1458             * special device it won't start with /, so move on to the next line.
1459             */
1460            if (*devname != '/') {
1461                chptr = strchr(chptr, '\n');
1462                if (chptr)
1463                    chptr++;
1464                continue;
1465            }
1466    
1467            /* Seek to the next space */
1468            chptr = strchr(chptr, ' ');
1469            if (!chptr) {
1470                fprintf(stderr, "grubby: error parsing %s: %s\n",
1471                        _PATH_MOUNTED, strerror(errno));
1472                return NULL;
1473            }
1474    
1475            /*
1476             * The second column of a mtab entry is the mount point, we are looking
1477             * for '/' obviously.
1478             */
1479            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1480                /* remember the last / entry in mtab */
1481               foundanswer = devname;
1482            }
1483    
1484            /* Next line */
1485            chptr = strchr(chptr, '\n');
1486            if (chptr)
1487                chptr++;
1488        }
1489    
1490        /* Return the last / entry found */
1491        if (foundanswer) {
1492            chptr = strchr(foundanswer, ' ');
1493            *chptr = '\0';
1494            return strdup(foundanswer);
1495        }
1496    
1497        return NULL;
1498    }
1499    
1500    void printEntry(struct singleEntry * entry) {
1501        int i;
1502        struct singleLine * line;
1503    
1504        for (line = entry->lines; line; line = line->next) {
1505     fprintf(stderr, "DBG: %s", line->indent);
1506     for (i = 0; i < line->numElements; i++) {
1507        /* Need to handle this, because we strip the quotes from
1508         * menuentry when read it. */
1509        if (line->type == LT_MENUENTRY && i == 1) {
1510     if(!isquote(*line->elements[i].item))
1511        fprintf(stderr, "\'%s\'", line->elements[i].item);
1512     else
1513        fprintf(stderr, "%s", line->elements[i].item);
1514     fprintf(stderr, "%s", line->elements[i].indent);
1515    
1516     continue;
1517        }
1518        
1519        fprintf(stderr, "%s%s",
1520        line->elements[i].item, line->elements[i].indent);
1521     }
1522     fprintf(stderr, "\n");
1523        }
1524    }
1525    
1526    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1527    {
1528        va_list argp;
1529    
1530        if (!debug)
1531     return;
1532    
1533        va_start(argp, fmt);
1534        fprintf(stderr, "DBG: Image entry failed: ");
1535        vfprintf(stderr, fmt, argp);
1536        printEntry(entry);
1537        va_end(argp);
1538    }
1539    
1540    #define beginswith(s, c) ((s) && (s)[0] == (c))
1541    
1542    static int endswith(const char *s, char c)
1543    {
1544     int slen;
1545    
1546     if (!s || !s[0])
1547     return 0;
1548     slen = strlen(s) - 1;
1549    
1550     return s[slen] == c;
1551    }
1552    
1553  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1554    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1555      struct singleLine * line;      struct singleLine * line;
1556      char * fullName;      char * fullName;
1557      int i;      int i;
     struct stat sb, sb2;  
1558      char * dev;      char * dev;
     char * end;  
1559      char * rootspec;      char * rootspec;
1560        char * rootdev;
1561    
1562      line = entry->lines;      if (skipRemoved && entry->skip) {
1563      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1564         return 0;
1565      if (!line) return 0;      }
1566      if (skipRemoved && entry->skip) return 0;  
1567      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1568        if (!line) {
1569     notSuitablePrintf(entry, "no line found\n");
1570     return 0;
1571        }
1572        if (line->numElements < 2) {
1573     notSuitablePrintf(entry, "line has only %d elements\n",
1574        line->numElements);
1575     return 0;
1576        }
1577    
1578      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1579    
1580      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1581        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1582      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1583      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1584              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1585                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1586      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1587                line->elements[1].item + rootspec_offset);
1588        if (access(fullName, R_OK)) {
1589     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1590     return 0;
1591        }
1592      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1593   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1594      if (i < line->numElements) {      if (i < line->numElements) {
1595   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1596      } else {      } else {
1597   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1598   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1599    
1600   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1601      dev = line->elements[1].item;      dev = line->elements[1].item;
1602   } else {   } else {
1603              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1604      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */       * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1605      line = entry->lines;       */
1606        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1607    
1608              /* failed to find one */              /* failed to find one */
1609              if (!line) return 0;              if (!line) {
1610     notSuitablePrintf(entry, "no line found\n");
1611     return 0;
1612                }
1613    
1614      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1615          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1616      if (i < line->numElements)      if (i < line->numElements)
1617          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1618      else {      else {
1619     notSuitablePrintf(entry, "no root= entry found\n");
1620   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1621          return 0;          return 0;
1622              }              }
1623   }   }
1624      }      }
1625    
1626      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1627   dev += 6;      if (!getpathbyspec(dev)) {
1628            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1629   /* check which device has this label */          return 0;
1630   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1631   if (!dev) return 0;   dev = getpathbyspec(dev);
1632    
1633        rootdev = findDiskForRoot();
1634        if (!rootdev) {
1635            notSuitablePrintf(entry, "can't find root device\n");
1636     return 0;
1637      }      }
1638    
1639      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1640   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1641      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1642      } else {          free(rootdev);
1643   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1644   if (*end) return 0;      }
1645    
1646        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1647            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1648     getuuidbydev(rootdev), getuuidbydev(dev));
1649     free(rootdev);
1650            return 0;
1651      }      }
     stat("/", &sb2);  
1652    
1653      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1654    
1655      return 1;      return 1;
1656  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1694  struct singleEntry * findEntryByPath(str
1694   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1695   if (!entry) return NULL;   if (!entry) return NULL;
1696    
1697   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1698   if (!line) return NULL;   if (!line) return NULL;
1699    
1700   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1732  struct singleEntry * findEntryByPath(str
1732    
1733   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1734      prefix = "";      prefix = "";
1735      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1736      kernel += 6;      kernel += 6;
1737   }   }
1738    
1739   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1740      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
   
1741    
1742      if (line && line->numElements >= 2 && !entry->skip) {      dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
                 rootspec = getRootSpecifier(line->elements[1].item);  
         if (!strcmp(line->elements[1].item  +  
                             ((rootspec != NULL) ? strlen(rootspec) : 0),  
                             kernel + strlen(prefix)))  
                     break;  
             }  
               
             /* have to check multiboot lines too */  
             if (entry->multiboot) {  
                 while (line && line->type != LT_MBMODULE) line = line->next;  
                 if (line && line->numElements >= 2 && !entry->skip) {  
                     rootspec = getRootSpecifier(line->elements[1].item);  
                     if (!strcmp(line->elements[1].item  +  
                                 ((rootspec != NULL) ? strlen(rootspec) : 0),  
                                 kernel + strlen(prefix)))  
                         break;  
                 }  
             }  
1743    
1744      i++;      /* check all the lines matching checkType */
1745        for (line = entry->lines; line; line = line->next) {
1746     line = getLineByType(entry->multiboot && checkType == LT_KERNEL ?
1747         LT_KERNEL|LT_MBMODULE|LT_HYPER :
1748         checkType, line);
1749     if (!line) break;  /* not found in this entry */
1750    
1751     if (line && line->type != LT_MENUENTRY &&
1752     line->numElements >= 2) {
1753        rootspec = getRootSpecifier(line->elements[1].item);
1754        if (!strcmp(line->elements[1].item +
1755     ((rootspec != NULL) ? strlen(rootspec) : 0),
1756     kernel + strlen(prefix)))
1757     break;
1758     }
1759     if(line->type == LT_MENUENTRY &&
1760     !strcmp(line->elements[1].item, kernel))
1761        break;
1762        }
1763    
1764        /* make sure this entry has a kernel identifier; this skips
1765         * non-Linux boot entries (could find netbsd etc, though, which is
1766         * unfortunate)
1767         */
1768        if (line && getLineByType(LT_KERNEL|LT_HYPER, entry->lines))
1769     break; /* found 'im! */
1770   }   }
1771    
1772   if (index) *index = i;   if (index) *index = i;
1773      }      }
1774    
     if (!entry) return NULL;  
   
     /* make sure this entry has a kernel identifier; this skips non-Linux  
        boot entries (could find netbsd etc, though, which is unfortunate) */  
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
     if (!line) {  
  if (!index) index = &i;  
  (*index)++;  
  return findEntryByPath(config, kernel, prefix, index);  
     }  
   
1775      return entry;      return entry;
1776  }  }
1777    
# Line 1200  void markRemovedImage(struct grubConfig Line 1850  void markRemovedImage(struct grubConfig
1850        const char * prefix) {        const char * prefix) {
1851      struct singleEntry * entry;      struct singleEntry * entry;
1852    
1853      if (!image) return;      if (!image)
1854     return;
1855    
1856        /* check and see if we're removing the default image */
1857        if (isdigit(*image)) {
1858     entry = findEntryByPath(cfg, image, prefix, NULL);
1859     if(entry)
1860        entry->skip = 1;
1861     return;
1862        }
1863    
1864      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1865   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1867  void markRemovedImage(struct grubConfig
1867    
1868  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1869       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1870       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1871      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1872      int i, j;      int i, j;
1873    
1874      if (newIsDefault) {      if (newIsDefault) {
1875   config->defaultImage = 0;   config->defaultImage = 0;
1876   return;   return;
1877        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1878     if (findEntryByIndex(config, index))
1879        config->defaultImage = index;
1880     else
1881        config->defaultImage = -1;
1882     return;
1883      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1884   i = 0;   i = 0;
1885   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1892  void setDefaultImage(struct grubConfig *
1892    
1893      /* 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
1894         changes */         changes */
1895      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1896     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1897        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1898        return;        return;
1899    
# Line 1286  void displayEntry(struct singleEntry * e Line 1952  void displayEntry(struct singleEntry * e
1952      char * root = NULL;      char * root = NULL;
1953      int i;      int i;
1954    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1955      printf("index=%d\n", index);      printf("index=%d\n", index);
1956    
1957      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
1958        if (!line) {
1959            printf("non linux entry\n");
1960            return;
1961        }
1962    
1963        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
1964     printf("kernel=%s\n", line->elements[1].item);
1965        else
1966     printf("kernel=%s%s\n", prefix, line->elements[1].item);
1967    
1968      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1969   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 1980  void displayEntry(struct singleEntry * e
1980   }   }
1981   printf("\"\n");   printf("\"\n");
1982      } else {      } else {
1983   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
1984   if (line) {   if (line) {
1985      char * s;      char * s;
1986    
# Line 1334  void displayEntry(struct singleEntry * e Line 2004  void displayEntry(struct singleEntry * e
2004      }      }
2005    
2006      if (!root) {      if (!root) {
2007   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2008   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2009      root=line->elements[1].item;      root=line->elements[1].item;
2010      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2019  void displayEntry(struct singleEntry * e
2019   printf("root=%s\n", s);   printf("root=%s\n", s);
2020      }      }
2021    
2022      line = entry->lines;      line = getLineByType(LT_INITRD, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2023    
2024      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2025   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2026        printf("initrd=");
2027     else
2028        printf("initrd=%s", prefix);
2029    
2030   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2031      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2032   printf("\n");   printf("\n");
2033      }      }
2034    
2035        line = getLineByType(LT_TITLE, entry->lines);
2036        if (line) {
2037     printf("title=%s\n", line->elements[1].item);
2038        } else {
2039     char * title;
2040     line = getLineByType(LT_MENUENTRY, entry->lines);
2041     title = grub2ExtractTitle(line);
2042     if (title)
2043        printf("title=%s\n", title);
2044        }
2045    }
2046    
2047    int isSuseSystem(void) {
2048        const char * path;
2049        const static char default_path[] = "/etc/SuSE-release";
2050    
2051        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2052     path = default_path;
2053    
2054        if (!access(path, R_OK))
2055     return 1;
2056        return 0;
2057    }
2058    
2059    int isSuseGrubConf(const char * path) {
2060        FILE * grubConf;
2061        char * line = NULL;
2062        size_t len = 0, res = 0;
2063    
2064        grubConf = fopen(path, "r");
2065        if (!grubConf) {
2066            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2067     return 0;
2068        }
2069    
2070        while ((res = getline(&line, &len, grubConf)) != -1) {
2071     if (!strncmp(line, "setup", 5)) {
2072        fclose(grubConf);
2073        free(line);
2074        return 1;
2075     }
2076        }
2077    
2078        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2079          path);
2080    
2081        fclose(grubConf);
2082        free(line);
2083        return 0;
2084    }
2085    
2086    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2087        FILE * grubConf;
2088        char * line = NULL;
2089        size_t res = 0, len = 0;
2090    
2091        if (!path) return 1;
2092        if (!lbaPtr) return 1;
2093    
2094        grubConf = fopen(path, "r");
2095        if (!grubConf) return 1;
2096    
2097        while ((res = getline(&line, &len, grubConf)) != -1) {
2098     if (line[res - 1] == '\n')
2099        line[res - 1] = '\0';
2100     else if (len > res)
2101        line[res] = '\0';
2102     else {
2103        line = realloc(line, res + 1);
2104        line[res] = '\0';
2105     }
2106    
2107     if (!strncmp(line, "setup", 5)) {
2108        if (strstr(line, "--force-lba")) {
2109            *lbaPtr = 1;
2110        } else {
2111            *lbaPtr = 0;
2112        }
2113        dbgPrintf("lba: %i\n", *lbaPtr);
2114        break;
2115     }
2116        }
2117    
2118        free(line);
2119        fclose(grubConf);
2120        return 0;
2121    }
2122    
2123    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2124        FILE * grubConf;
2125        char * line = NULL;
2126        size_t res = 0, len = 0;
2127        char * lastParamPtr = NULL;
2128        char * secLastParamPtr = NULL;
2129        char installDeviceNumber = '\0';
2130        char * bounds = NULL;
2131    
2132        if (!path) return 1;
2133        if (!devicePtr) return 1;
2134    
2135        grubConf = fopen(path, "r");
2136        if (!grubConf) return 1;
2137    
2138        while ((res = getline(&line, &len, grubConf)) != -1) {
2139     if (strncmp(line, "setup", 5))
2140        continue;
2141    
2142     if (line[res - 1] == '\n')
2143        line[res - 1] = '\0';
2144     else if (len > res)
2145        line[res] = '\0';
2146     else {
2147        line = realloc(line, res + 1);
2148        line[res] = '\0';
2149     }
2150    
2151     lastParamPtr = bounds = line + res;
2152    
2153     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2154     while (!isspace(*lastParamPtr))
2155        lastParamPtr--;
2156     lastParamPtr++;
2157    
2158     secLastParamPtr = lastParamPtr - 2;
2159     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2160    
2161     if (lastParamPtr + 3 > bounds) {
2162        dbgPrintf("lastParamPtr going over boundary");
2163        fclose(grubConf);
2164        free(line);
2165        return 1;
2166     }
2167     if (!strncmp(lastParamPtr, "(hd", 3))
2168        lastParamPtr += 3;
2169     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2170    
2171     /*
2172     * Second last parameter will decide wether last parameter is
2173     * an IMAGE_DEVICE or INSTALL_DEVICE
2174     */
2175     while (!isspace(*secLastParamPtr))
2176        secLastParamPtr--;
2177     secLastParamPtr++;
2178    
2179     if (secLastParamPtr + 3 > bounds) {
2180        dbgPrintf("secLastParamPtr going over boundary");
2181        fclose(grubConf);
2182        free(line);
2183        return 1;
2184     }
2185     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2186     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2187        secLastParamPtr += 3;
2188        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2189        installDeviceNumber = *secLastParamPtr;
2190     } else {
2191        installDeviceNumber = *lastParamPtr;
2192     }
2193    
2194     *devicePtr = malloc(6);
2195     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2196     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2197     fclose(grubConf);
2198     free(line);
2199     return 0;
2200        }
2201    
2202        free(line);
2203        fclose(grubConf);
2204        return 1;
2205    }
2206    
2207    int grubGetBootFromDeviceMap(const char * device,
2208         char ** bootPtr) {
2209        FILE * deviceMap;
2210        char * line = NULL;
2211        size_t res = 0, len = 0;
2212        char * devicePtr;
2213        char * bounds = NULL;
2214        const char * path;
2215        const static char default_path[] = "/boot/grub/device.map";
2216    
2217        if (!device) return 1;
2218        if (!bootPtr) return 1;
2219    
2220        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2221     path = default_path;
2222    
2223        dbgPrintf("opening grub device.map file from: %s\n", path);
2224        deviceMap = fopen(path, "r");
2225        if (!deviceMap)
2226     return 1;
2227    
2228        while ((res = getline(&line, &len, deviceMap)) != -1) {
2229            if (!strncmp(line, "#", 1))
2230        continue;
2231    
2232     if (line[res - 1] == '\n')
2233        line[res - 1] = '\0';
2234     else if (len > res)
2235        line[res] = '\0';
2236     else {
2237        line = realloc(line, res + 1);
2238        line[res] = '\0';
2239     }
2240    
2241     devicePtr = line;
2242     bounds = line + res;
2243    
2244     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2245        devicePtr++;
2246     dbgPrintf("device: %s\n", devicePtr);
2247    
2248     if (!strncmp(devicePtr, device, strlen(device))) {
2249        devicePtr += strlen(device);
2250        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2251            devicePtr++;
2252    
2253        *bootPtr = strdup(devicePtr);
2254        break;
2255     }
2256        }
2257    
2258        free(line);
2259        fclose(deviceMap);
2260        return 0;
2261    }
2262    
2263    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2264        char * grubDevice;
2265    
2266        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2267     dbgPrintf("error looking for grub installation device\n");
2268        else
2269     dbgPrintf("grubby installation device: %s\n", grubDevice);
2270    
2271        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2272     dbgPrintf("error looking for grub boot device\n");
2273        else
2274     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2275    
2276        free(grubDevice);
2277        return 0;
2278    }
2279    
2280    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2281        /*
2282         * This SuSE grub configuration file at this location is not your average
2283         * grub configuration file, but instead the grub commands used to setup
2284         * grub on that system.
2285         */
2286        const char * path;
2287        const static char default_path[] = "/etc/grub.conf";
2288    
2289        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2290     path = default_path;
2291    
2292        if (!isSuseGrubConf(path)) return 1;
2293    
2294        if (lbaPtr) {
2295            *lbaPtr = 0;
2296            if (suseGrubConfGetLba(path, lbaPtr))
2297                return 1;
2298        }
2299    
2300        if (bootPtr) {
2301            *bootPtr = NULL;
2302            suseGrubConfGetBoot(path, bootPtr);
2303        }
2304    
2305        return 0;
2306  }  }
2307    
2308  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2312  int parseSysconfigGrub(int * lbaPtr, cha
2312      char * start;      char * start;
2313      char * param;      char * param;
2314    
2315      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2316      if (!in) return 1;      if (!in) return 1;
2317    
2318      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2353  int parseSysconfigGrub(int * lbaPtr, cha
2353  }  }
2354    
2355  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2356      char * boot;      char * boot = NULL;
2357      int lba;      int lba;
2358    
2359      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2360   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2361   if (boot) printf("boot=%s\n", boot);      free(boot);
2362        return;
2363     }
2364        } else {
2365            if (parseSysconfigGrub(&lba, &boot)) {
2366        free(boot);
2367        return;
2368     }
2369        }
2370    
2371        if (lba) printf("lba\n");
2372        if (boot) {
2373     printf("boot=%s\n", boot);
2374     free(boot);
2375      }      }
2376  }  }
2377    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2387  int displayInfo(struct grubConfig * conf
2387   return 1;   return 1;
2388      }      }
2389    
2390      /* 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
2391         be a better way */         be a better way */
2392      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2393   dumpSysconfigGrub();   dumpSysconfigGrub();
2394      } else {      } else {
2395   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2396   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2397      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2398   }   }
2399    
2400   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2401   if (line) printf("lba\n");   if (line) printf("lba\n");
2402      }      }
2403    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2412  int displayInfo(struct grubConfig * conf
2412      return 0;      return 0;
2413  }  }
2414    
2415    struct singleLine * addLineTmpl(struct singleEntry * entry,
2416     struct singleLine * tmplLine,
2417     struct singleLine * prevLine,
2418     const char * val,
2419     struct configFileInfo * cfi)
2420    {
2421        struct singleLine * newLine = lineDup(tmplLine);
2422    
2423        if (val) {
2424     /* override the inherited value with our own.
2425     * This is a little weak because it only applies to elements[1]
2426     */
2427     if (newLine->numElements > 1)
2428        removeElement(newLine, 1);
2429     insertElement(newLine, val, 1, cfi);
2430    
2431     /* but try to keep the rootspec from the template... sigh */
2432     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD)) {
2433        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2434        if (rootspec != NULL) {
2435     free(newLine->elements[1].item);
2436     newLine->elements[1].item =
2437        sdupprintf("%s%s", rootspec, val);
2438        }
2439     }
2440        }
2441    
2442        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2443          newLine->elements[0].item : "");
2444    
2445        if (!entry->lines) {
2446     /* first one on the list */
2447     entry->lines = newLine;
2448        } else if (prevLine) {
2449     /* add after prevLine */
2450     newLine->next = prevLine->next;
2451     prevLine->next = newLine;
2452        }
2453    
2454        return newLine;
2455    }
2456    
2457  /* val may be NULL */  /* val may be NULL */
2458  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2459       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2460       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2461       char * val) {       const char * val) {
2462      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2463      int i;      struct keywordTypes * kw;
2464        struct singleLine tmpl;
2465    
2466      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2467   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2468      if (type != LT_TITLE || !cfi->titleBracketed)       */
2469          if (!cfi->keywords[i].key) abort();  
2470        if (type == LT_TITLE && cfi->titleBracketed) {
2471     /* we're doing a bracketed title (zipl) */
2472     tmpl.type = type;
2473     tmpl.numElements = 1;
2474     tmpl.elements = alloca(sizeof(*tmpl.elements));
2475     tmpl.elements[0].item = alloca(strlen(val)+3);
2476     sprintf(tmpl.elements[0].item, "[%s]", val);
2477     tmpl.elements[0].indent = "";
2478     val = NULL;
2479        } else if (type == LT_MENUENTRY) {
2480     char *lineend = "--class gnu-linux --class gnu --class os {";
2481     if (!val) {
2482        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2483        abort();
2484     }
2485     kw = getKeywordByType(type, cfi);
2486     if (!kw) {
2487        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2488        abort();
2489     }
2490     tmpl.indent = "";
2491     tmpl.type = type;
2492     tmpl.numElements = 3;
2493     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2494     tmpl.elements[0].item = kw->key;
2495     tmpl.elements[0].indent = alloca(2);
2496     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2497     tmpl.elements[1].item = (char *)val;
2498     tmpl.elements[1].indent = alloca(2);
2499     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2500     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2501     strcpy(tmpl.elements[2].item, lineend);
2502     tmpl.elements[2].indent = "";
2503        } else {
2504     kw = getKeywordByType(type, cfi);
2505     if (!kw) {
2506        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2507        abort();
2508     }
2509     tmpl.type = type;
2510     tmpl.numElements = val ? 2 : 1;
2511     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2512     tmpl.elements[0].item = kw->key;
2513     tmpl.elements[0].indent = alloca(2);
2514     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2515     if (val) {
2516        tmpl.elements[1].item = (char *)val;
2517        tmpl.elements[1].indent = "";
2518     }
2519        }
2520    
2521      /* 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
2522         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2523         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
2524         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2525         differently from the rest) */         differently from the rest) */
2526      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2527   line = entry->lines;   if (line->numElements) prev = line;
2528   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2529   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;  
2530      }      }
2531    
2532      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2533          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2534          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2535          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2536          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2537          line->elements[0].indent = malloc(2);   else
2538          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2539          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2540             if (menuEntry)
2541          if (val) {      tmpl.indent = "\t";
2542              line->elements[1].item = val;   else if (prev == entry->lines)
2543              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2544          }   else
2545      } 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("");  
2546      }      }
2547    
2548      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2549  }  }
2550    
2551  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2570  void removeLine(struct singleEntry * ent
2570      free(line);      free(line);
2571  }  }
2572    
2573    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2574    {
2575        struct singleLine newLine = {
2576     .indent = tmplLine->indent,
2577     .type = tmplLine->type,
2578     .next = tmplLine->next,
2579        };
2580        int firstQuotedItem = -1;
2581        int quoteLen = 0;
2582        int j;
2583        int element = 0;
2584        char *c;
2585    
2586        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2587        strcpy(c, tmplLine->elements[0].item);
2588        insertElement(&newLine, c, element++, cfi);
2589        free(c);
2590        c = NULL;
2591    
2592        for (j = 1; j < tmplLine->numElements; j++) {
2593     if (firstQuotedItem == -1) {
2594        quoteLen += strlen(tmplLine->elements[j].item);
2595        
2596        if (isquote(tmplLine->elements[j].item[0])) {
2597     firstQuotedItem = j;
2598            quoteLen += strlen(tmplLine->elements[j].indent);
2599        } else {
2600     c = malloc(quoteLen + 1);
2601     strcpy(c, tmplLine->elements[j].item);
2602     insertElement(&newLine, c, element++, cfi);
2603     free(c);
2604     quoteLen = 0;
2605        }
2606     } else {
2607        int itemlen = strlen(tmplLine->elements[j].item);
2608        quoteLen += itemlen;
2609        quoteLen += strlen(tmplLine->elements[j].indent);
2610        
2611        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2612     c = malloc(quoteLen + 1);
2613     c[0] = '\0';
2614     for (int i = firstQuotedItem; i < j+1; i++) {
2615        strcat(c, tmplLine->elements[i].item);
2616        strcat(c, tmplLine->elements[i].indent);
2617     }
2618     insertElement(&newLine, c, element++, cfi);
2619     free(c);
2620    
2621     firstQuotedItem = -1;
2622     quoteLen = 0;
2623        }
2624     }
2625        }
2626        while (tmplLine->numElements)
2627     removeElement(tmplLine, 0);
2628        if (tmplLine->elements)
2629     free(tmplLine->elements);
2630    
2631        tmplLine->numElements = newLine.numElements;
2632        tmplLine->elements = newLine.elements;
2633    }
2634    
2635    static void insertElement(struct singleLine * line,
2636      const char * item, int insertHere,
2637      struct configFileInfo * cfi)
2638    {
2639        struct keywordTypes * kw;
2640        char indent[2] = "";
2641    
2642        /* sanity check */
2643        if (insertHere > line->numElements) {
2644     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2645      insertHere, line->numElements);
2646     insertHere = line->numElements;
2647        }
2648    
2649        line->elements = realloc(line->elements, (line->numElements + 1) *
2650         sizeof(*line->elements));
2651        memmove(&line->elements[insertHere+1],
2652        &line->elements[insertHere],
2653        (line->numElements - insertHere) *
2654        sizeof(*line->elements));
2655        line->elements[insertHere].item = strdup(item);
2656    
2657        kw = getKeywordByType(line->type, cfi);
2658    
2659        if (line->numElements == 0) {
2660     indent[0] = '\0';
2661        } else if (insertHere == 0) {
2662     indent[0] = kw->nextChar;
2663        } else if (kw->separatorChar != '\0') {
2664     indent[0] = kw->separatorChar;
2665        } else {
2666     indent[0] = ' ';
2667        }
2668    
2669        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2670     /* move the end-of-line forward */
2671     line->elements[insertHere].indent =
2672        line->elements[insertHere-1].indent;
2673     line->elements[insertHere-1].indent = strdup(indent);
2674        } else {
2675     line->elements[insertHere].indent = strdup(indent);
2676        }
2677    
2678        line->numElements++;
2679    
2680        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2681          line->elements[0].item,
2682          line->elements[insertHere].item,
2683          line->elements[insertHere].indent,
2684          insertHere);
2685    }
2686    
2687    static void removeElement(struct singleLine * line, int removeHere) {
2688        int i;
2689    
2690        /* sanity check */
2691        if (removeHere >= line->numElements) return;
2692    
2693        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2694          removeHere, line->elements[removeHere].item);
2695    
2696        free(line->elements[removeHere].item);
2697    
2698        if (removeHere > 1) {
2699     /* previous argument gets this argument's post-indentation */
2700     free(line->elements[removeHere-1].indent);
2701     line->elements[removeHere-1].indent =
2702        line->elements[removeHere].indent;
2703        } else {
2704     free(line->elements[removeHere].indent);
2705        }
2706    
2707        /* now collapse the array, but don't bother to realloc smaller */
2708        for (i = removeHere; i < line->numElements - 1; i++)
2709     line->elements[i] = line->elements[i + 1];
2710    
2711        line->numElements--;
2712    }
2713    
2714  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2715      char * first, * second;      char * first, * second;
2716      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2733  int updateActualImage(struct grubConfig
2733      struct singleEntry * entry;      struct singleEntry * entry;
2734      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2735      int index = 0;      int index = 0;
2736      int i, j, k;      int i, k;
2737      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2738      const char ** arg;      const char ** arg;
2739      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2740      int firstElement;      int firstElement;
2741      int *usedElements, *usedArgs;      int *usedElements;
2742        int doreplace;
2743    
2744      if (!image) return 0;      if (!image) return 0;
2745    
# Line 1609  int updateActualImage(struct grubConfig Line 2766  int updateActualImage(struct grubConfig
2766   }   }
2767      }      }
2768    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2769    
2770      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2771   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2772    
2773      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2774   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2775    
2776      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2777    
2778      k = 0;   if (multibootArgs && !entry->multiboot)
2779      for (arg = newArgs; *arg; arg++)      continue;
2780          k++;  
2781      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2782     * LT_KERNELARGS, use that.  Otherwise use
2783     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2784     */
2785     if (useKernelArgs) {
2786        line = getLineByType(LT_KERNELARGS, entry->lines);
2787        if (!line) {
2788     /* no LT_KERNELARGS, need to add it */
2789     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2790           cfg->secondaryIndent, NULL);
2791        }
2792        firstElement = 1;
2793    
2794      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2795   index++;      line = getLineByType(LT_HYPER, entry->lines);
2796        if (!line) {
2797     /* a multiboot entry without LT_HYPER? */
2798     continue;
2799        }
2800        firstElement = 2;
2801    
2802   line = entry->lines;   } else {
2803   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE, entry->lines);
2804   if (!line) continue;      if (!line) {
2805   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2806     continue;
2807          if (entry->multiboot && !multibootArgs) {      }
2808              /* 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;  
2809   }   }
2810    
2811   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2812      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2813      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2814     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2815        /* this is a multiboot entry, make sure there's
2816         * -- on the args line
2817         */
2818        for (i = firstElement; i < line->numElements; i++) {
2819     if (!strcmp(line->elements[i].item, "--"))
2820        break;
2821        }
2822        if (i == line->numElements) {
2823     /* assume all existing args are kernel args,
2824     * prepend -- to make it official
2825     */
2826     insertElement(line, "--", firstElement, cfg->cfi);
2827     i = firstElement;
2828        }
2829        if (!multibootArgs) {
2830     /* kernel args start after the -- */
2831     firstElement = i + 1;
2832        }
2833     } else if (cfg->cfi->mbConcatArgs) {
2834        /* this is a non-multiboot entry, remove hyper args */
2835        for (i = firstElement; i < line->numElements; i++) {
2836     if (!strcmp(line->elements[i].item, "--"))
2837        break;
2838        }
2839        if (i < line->numElements) {
2840     /* remove args up to -- */
2841     while (strcmp(line->elements[firstElement].item, "--"))
2842        removeElement(line, firstElement);
2843     /* remove -- */
2844     removeElement(line, firstElement);
2845        }
2846   }   }
2847    
2848          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2849    
2850          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2851   for (arg = newArgs; *arg; arg++) {  
2852              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2853      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2854     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2855        !strcmp(line->elements[i].item, "--"))
2856     {
2857        /* reached the end of hyper args, insert here */
2858        doreplace = 0;
2859        break;  
2860     }
2861                  if (usedElements[i])                  if (usedElements[i])
2862                      continue;                      continue;
2863   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2864                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2865      break;      break;
2866                  }                  }
2867              }              }
     chptr = strchr(*arg, '=');  
2868    
2869      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2870   /* replace */   /* direct replacement */
2871   free(line->elements[i].item);   free(line->elements[i].item);
2872   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("");  
  }  
2873    
2874   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2875   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2876      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2877   /* append */   if (rootLine) {
2878   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2879   (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(" ");  
2880   } else {   } else {
2881      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2882         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2883   }   }
2884        }
2885    
2886   line->numElements++;      else {
2887     /* insert/append */
2888     insertElement(line, *arg, i, cfg->cfi);
2889     usedElements = realloc(usedElements, line->numElements *
2890           sizeof(*usedElements));
2891     memmove(&usedElements[i + 1], &usedElements[i],
2892     line->numElements - i - 1);
2893     usedElements[i] = 1;
2894    
2895   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2896     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2897     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2898   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2899      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2900      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2901   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2902   }   }
2903      }      }
             k++;  
2904   }   }
2905    
2906          free(usedElements);          free(usedElements);
2907    
  /* 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? */  
2908   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2909      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2910   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2911        !strcmp(line->elements[i].item, "--"))
2912        /* reached the end of hyper args, stop here */
2913        break;
2914     if (!argMatch(line->elements[i].item, *arg)) {
2915        removeElement(line, i);
2916      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;  
2917   }   }
2918        }
2919   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2920        if (useRoot && !strncmp(*arg, "root=", 5)) {
2921   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2922      line->elements[j - 1] = line->elements[j];   if (rootLine)
2923        removeLine(entry, rootLine);
  line->numElements--;  
2924      }      }
2925   }   }
2926    
# Line 1760  int updateActualImage(struct grubConfig Line 2931  int updateActualImage(struct grubConfig
2931   }   }
2932      }      }
2933    
     free(usedArgs);  
2934      free(newArgs);      free(newArgs);
2935      free(oldArgs);      free(oldArgs);
2936    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2956  int updateImage(struct grubConfig * cfg,
2956      return rc;      return rc;
2957  }  }
2958    
2959    int updateInitrd(struct grubConfig * cfg, const char * image,
2960                     const char * prefix, const char * initrd) {
2961        struct singleEntry * entry;
2962        struct singleLine * line, * kernelLine, *endLine = NULL;
2963        int index = 0;
2964    
2965        if (!image) return 0;
2966    
2967        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
2968            kernelLine = getLineByType(LT_KERNEL, entry->lines);
2969            if (!kernelLine) continue;
2970    
2971            line = getLineByType(LT_INITRD, entry->lines);
2972            if (line)
2973                removeLine(entry, line);
2974            if (prefix) {
2975                int prefixLen = strlen(prefix);
2976                if (!strncmp(initrd, prefix, prefixLen))
2977                    initrd += prefixLen;
2978            }
2979     endLine = getLineByType(LT_ENTRY_END, entry->lines);
2980     if (endLine)
2981        removeLine(entry, endLine);
2982            line = addLine(entry, cfg->cfi, LT_INITRD, kernelLine->indent, initrd);
2983            if (!line)
2984        return 1;
2985     if (endLine) {
2986        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
2987                if (!line)
2988     return 1;
2989     }
2990    
2991            break;
2992        }
2993    
2994        return 0;
2995    }
2996    
2997  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
2998      int fd;      int fd;
2999      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3017  int checkDeviceBootloader(const char * d
3017      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3018   return 0;   return 0;
3019    
3020      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3021   offset = boot[2] + 2;   offset = boot[2] + 2;
3022      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3023   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3024      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3025   offset = boot[1] + 2;        offset = boot[1] + 2;
3026            /*
3027     * it looks like grub, when copying stage1 into the mbr, patches stage1
3028     * right after the JMP location, replacing other instructions such as
3029     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3030     * different bytes.
3031     */
3032          if ((bootSect[offset + 1] == NOOP_OPCODE)
3033      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3034     offset = offset + 3;
3035          }
3036      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3037   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3038      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3174  int checkForLilo(struct grubConfig * con
3174      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3175  }  }
3176    
3177    int checkForGrub2(struct grubConfig * config) {
3178        if (!access("/etc/grub.d/", R_OK))
3179     return 2;
3180    
3181        return 1;
3182    }
3183    
3184  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3185      int fd;      int fd;
3186      unsigned char bootSect[512];      unsigned char bootSect[512];
3187      char * boot;      char * boot;
3188        int onSuse = isSuseSystem();
3189    
3190      if (parseSysconfigGrub(NULL, &boot))  
3191   return 0;      if (onSuse) {
3192     if (parseSuseGrubConf(NULL, &boot))
3193        return 0;
3194        } else {
3195     if (parseSysconfigGrub(NULL, &boot))
3196        return 0;
3197        }
3198    
3199      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3200      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3208  int checkForGrub(struct grubConfig * con
3208      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3209   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3210   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3211     close(fd);
3212   return 1;   return 1;
3213      }      }
3214      close(fd);      close(fd);
3215    
3216        /* The more elaborate checks do not work on SuSE. The checks done
3217         * seem to be reasonble (at least for now), so just return success
3218         */
3219        if (onSuse)
3220     return 2;
3221    
3222      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3223  }  }
3224    
3225    int checkForExtLinux(struct grubConfig * config) {
3226        int fd;
3227        unsigned char bootSect[512];
3228        char * boot;
3229        char executable[] = "/boot/extlinux/extlinux";
3230    
3231        printf("entered: checkForExtLinux()\n");
3232    
3233        if (parseSysconfigGrub(NULL, &boot))
3234     return 0;
3235    
3236        /* assume grub is not installed -- not an error condition */
3237        if (!boot)
3238     return 0;
3239    
3240        fd = open(executable, O_RDONLY);
3241        if (fd < 0)
3242     /* this doesn't exist if grub hasn't been installed */
3243     return 0;
3244    
3245        if (read(fd, bootSect, 512) != 512) {
3246     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3247     executable, strerror(errno));
3248     return 1;
3249        }
3250        close(fd);
3251    
3252        return checkDeviceBootloader(boot, bootSect);
3253    }
3254    
3255    int checkForYaboot(struct grubConfig * config) {
3256        /*
3257         * This is a simplistic check that we consider good enough for own puporses
3258         *
3259         * If we were to properly check if yaboot is *installed* we'd need to:
3260         * 1) get the system boot device (LT_BOOT)
3261         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3262         *    the content on the boot device
3263         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3264         * 4) check again if binary and boot device contents match
3265         */
3266        if (!access("/etc/yaboot.conf", R_OK))
3267     return 2;
3268    
3269        return 1;
3270    }
3271    
3272    int checkForElilo(struct grubConfig * config) {
3273        if (!access("/etc/elilo.conf", R_OK))
3274     return 2;
3275    
3276        return 1;
3277    }
3278    
3279  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3280      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3281    
# Line 1994  static char * getRootSpecifier(char * st Line 3287  static char * getRootSpecifier(char * st
3287      return rootspec;      return rootspec;
3288  }  }
3289    
3290    static char * getInitrdVal(struct grubConfig * config,
3291       const char * prefix, struct singleLine *tmplLine,
3292       const char * newKernelInitrd,
3293       const char ** extraInitrds, int extraInitrdCount)
3294    {
3295        char *initrdVal, *end;
3296        int i;
3297        size_t totalSize;
3298        size_t prefixLen;
3299        char separatorChar;
3300    
3301        prefixLen = strlen(prefix);
3302        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3303    
3304        for (i = 0; i < extraInitrdCount; i++) {
3305     totalSize += sizeof(separatorChar);
3306     totalSize += strlen(extraInitrds[i]) - prefixLen;
3307        }
3308    
3309        initrdVal = end = malloc(totalSize);
3310    
3311        end = stpcpy (end, newKernelInitrd + prefixLen);
3312    
3313        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3314        for (i = 0; i < extraInitrdCount; i++) {
3315     const char *extraInitrd;
3316     int j;
3317    
3318     extraInitrd = extraInitrds[i] + prefixLen;
3319     /* Don't add entries that are already there */
3320     if (tmplLine != NULL) {
3321        for (j = 2; j < tmplLine->numElements; j++)
3322     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3323        break;
3324    
3325        if (j != tmplLine->numElements)
3326     continue;
3327     }
3328    
3329     *end++ = separatorChar;
3330     end = stpcpy(end, extraInitrd);
3331        }
3332    
3333        return initrdVal;
3334    }
3335    
3336  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3337           const char * prefix,           const char * prefix,
3338   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3339   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3340                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3341                     const char * newMBKernel, const char * newMBKernelArgs) {
3342      struct singleEntry * new;      struct singleEntry * new;
3343      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3344      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3345      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3346    
3347      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3348    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3372  int addNewKernel(struct grubConfig * con
3372      config->entries = new;      config->entries = new;
3373    
3374      /* copy/update from the template */      /* copy/update from the template */
3375      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3376        if (newKernelInitrd)
3377     needs |= NEED_INITRD;
3378      if (newMBKernel) {      if (newMBKernel) {
3379          needs |= KERNEL_MB;          needs |= NEED_MB;
3380          new->multiboot = 1;          new->multiboot = 1;
3381      }      }
3382    
3383      if (template) {      if (template) {
3384   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3385      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3386      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3387   indent = tmplLine->indent;   {
3388        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3389    
3390      /* skip comments */      /* skip comments */
3391      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3392      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3393      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3394    
3395      /* we don't need an initrd here */      if (tmplLine->type == LT_KERNEL &&
3396      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;      tmplLine->numElements >= 2) {
3397     if (!template->multiboot && (needs & NEED_MB)) {
3398              if (tmplLine->type == LT_KERNEL &&      /* it's not a multiboot template and this is the kernel
3399                  !template->multiboot && (needs & KERNEL_MB)) {       * line.  Try to be intelligent about inserting the
3400                  struct singleLine *l;       * hypervisor at the same time.
3401                  needs &= ~ KERNEL_MB;       */
3402        if (config->cfi->mbHyperFirst) {
3403                  l = addLine(new, config->cfi, LT_KERNEL,   /* insert the hypervisor first */
3404                                    config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3405                                    newMBKernel + strlen(prefix));    tmplLine->indent,
3406                      newMBKernel + strlen(prefix));
3407                  tmplLine = lastLine;   /* set up for adding the kernel line */
3408                  if (!new->lines) {   free(tmplLine->indent);
3409                      new->lines = l;   tmplLine->indent = strdup(config->secondaryIndent);
3410                  } else {   needs &= ~NEED_MB;
3411                      newLine->next = l;      }
3412                      newLine = l;      if (needs & NEED_KERNEL) {
3413                  }   /* use addLineTmpl to preserve line elements,
3414                  continue;   * otherwise we could just call addLine.  Unfortunately
3415              } else if (tmplLine->type == LT_KERNEL &&   * this means making some changes to the template
3416                         template->multiboot && !new->multiboot) {   * such as the indent change above and the type
3417                  continue; /* don't need multiboot kernel here */   * change below.
3418              }   */
3419     struct keywordTypes * mbm_kw =
3420        getKeywordByType(LT_MBMODULE, config->cfi);
3421     if (mbm_kw) {
3422        tmplLine->type = LT_MBMODULE;
3423        free(tmplLine->elements[0].item);
3424        tmplLine->elements[0].item = strdup(mbm_kw->key);
3425     }
3426     newLine = addLineTmpl(new, tmplLine, newLine,
3427          newKernelPath + strlen(prefix), config->cfi);
3428     needs &= ~NEED_KERNEL;
3429        }
3430        if (needs & NEED_MB) { /* !mbHyperFirst */
3431     newLine = addLine(new, config->cfi, LT_HYPER,
3432      config->secondaryIndent,
3433      newMBKernel + strlen(prefix));
3434     needs &= ~NEED_MB;
3435        }
3436     } else if (needs & NEED_KERNEL) {
3437        newLine = addLineTmpl(new, tmplLine, newLine,
3438      newKernelPath + strlen(prefix), config->cfi);
3439        needs &= ~NEED_KERNEL;
3440     }
3441    
3442      if (!new->lines) {      } else if (tmplLine->type == LT_HYPER &&
3443   newLine = malloc(sizeof(*newLine));         tmplLine->numElements >= 2) {
3444   new->lines = newLine;   if (needs & NEED_MB) {
3445      } else {      newLine = addLineTmpl(new, tmplLine, newLine,
3446   newLine->next = malloc(sizeof(*newLine));    newMBKernel + strlen(prefix), config->cfi);
3447   newLine = newLine->next;      needs &= ~NEED_MB;
3448      }   }
3449    
3450        } else if (tmplLine->type == LT_MBMODULE &&
3451           tmplLine->numElements >= 2) {
3452     if (new->multiboot) {
3453        if (needs & NEED_KERNEL) {
3454     newLine = addLineTmpl(new, tmplLine, newLine,
3455          newKernelPath +
3456          strlen(prefix), config->cfi);
3457     needs &= ~NEED_KERNEL;
3458        } else if (config->cfi->mbInitRdIsModule &&
3459           (needs & NEED_INITRD)) {
3460     char *initrdVal;
3461     initrdVal = getInitrdVal(config, prefix, tmplLine,
3462     newKernelInitrd, extraInitrds,
3463     extraInitrdCount);
3464     newLine = addLineTmpl(new, tmplLine, newLine,
3465          initrdVal, config->cfi);
3466     free(initrdVal);
3467     needs &= ~NEED_INITRD;
3468        }
3469     } else if (needs & NEED_KERNEL) {
3470        /* template is multi but new is not,
3471         * insert the kernel in the first module slot
3472         */
3473        tmplLine->type = LT_KERNEL;
3474        free(tmplLine->elements[0].item);
3475        tmplLine->elements[0].item =
3476     strdup(getKeywordByType(LT_KERNEL, config->cfi)->key);
3477        newLine = addLineTmpl(new, tmplLine, newLine,
3478      newKernelPath + strlen(prefix), config->cfi);
3479        needs &= ~NEED_KERNEL;
3480     } else if (needs & NEED_INITRD) {
3481        char *initrdVal;
3482        /* template is multi but new is not,
3483         * insert the initrd in the second module slot
3484         */
3485        tmplLine->type = LT_INITRD;
3486        free(tmplLine->elements[0].item);
3487        tmplLine->elements[0].item =
3488     strdup(getKeywordByType(LT_INITRD, config->cfi)->key);
3489        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3490        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3491        free(initrdVal);
3492        needs &= ~NEED_INITRD;
3493     }
3494    
     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));  
                 }  
3495      } else if (tmplLine->type == LT_INITRD &&      } else if (tmplLine->type == LT_INITRD &&
3496      tmplLine->numElements >= 2) {         tmplLine->numElements >= 2) {
3497   needs &= ~KERNEL_INITRD;   if (needs & NEED_INITRD &&
3498   free(newLine->elements[1].item);      new->multiboot && !template->multiboot &&
3499                  if (new->multiboot && !template->multiboot) {      config->cfi->mbInitRdIsModule) {
3500                      free(newLine->elements[0].item);      /* make sure we don't insert the module initrd
3501                      newLine->elements[0].item = strdup("module");       * before the module kernel... if we don't do it here,
3502                      newLine->type = LT_MBMODULE;       * it will be inserted following the template.
3503                  }       */
3504                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      if (!needs & NEED_KERNEL) {
3505                  if (rootspec != NULL) {   char *initrdVal;
3506                      newLine->elements[1].item = sdupprintf("%s%s",  
3507                                                             rootspec,   initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3508                                                             newKernelInitrd +   newLine = addLine(new, config->cfi, LT_MBMODULE,
3509                                                             strlen(prefix));    config->secondaryIndent,
3510                  } else {    initrdVal);
3511                      newLine->elements[1].item = strdup(newKernelInitrd +   free(initrdVal);
3512                                                         strlen(prefix));   needs &= ~NEED_INITRD;
3513                  }      }
3514              } else if (tmplLine->type == LT_MBMODULE &&   } else if (needs & NEED_INITRD) {
3515                         tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {      char *initrdVal;
3516   needs &= ~KERNEL_INITRD;      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3517                  if (!new->multiboot && template->multiboot) {      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3518                      free(newLine->elements[0].item);      free(initrdVal);
3519                      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);  
3520   }   }
3521    
3522   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3523   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3524   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3525     char *nkt = malloc(strlen(newKernelTitle)+3);
3526     strcpy(nkt, "'");
3527     strcat(nkt, newKernelTitle);
3528     strcat(nkt, "'");
3529     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3530     free(nkt);
3531     needs &= ~NEED_TITLE;
3532      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3533                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3534                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3535                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3536                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3537                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3538                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3539                                             newLine->numElements);     config->cfi->titleBracketed) {
3540        /* addLineTmpl doesn't handle titleBracketed */
3541                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3542                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3543                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3544                  newLine->numElements = 1;   }
3545              }      } else if (tmplLine->type == LT_ECHO) {
3546        requote(tmplLine, config->cfi);
3547        static const char *prefix = "'Loading ";
3548        if (tmplLine->numElements > 1 &&
3549        strstr(tmplLine->elements[1].item, prefix) &&
3550        masterLine->next && masterLine->next->type == LT_KERNEL) {
3551     char *newTitle = malloc(strlen(prefix) +
3552     strlen(newKernelTitle) + 2);
3553    
3554     strcpy(newTitle, prefix);
3555     strcat(newTitle, newKernelTitle);
3556     strcat(newTitle, "'");
3557     newLine = addLine(new, config->cfi, LT_ECHO,
3558     tmplLine->indent, newTitle);
3559     free(newTitle);
3560        } else {
3561     /* pass through other lines from the template */
3562     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3563     config->cfi);
3564        }
3565        } else {
3566     /* pass through other lines from the template */
3567     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3568        }
3569   }   }
3570    
3571      } else {      } else {
3572   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3573      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3574     */
3575     switch (config->cfi->entryStart) {
3576        case LT_KERNEL:
3577     if (new->multiboot && config->cfi->mbHyperFirst) {
3578        /* fall through to LT_HYPER */
3579     } else {
3580        newLine = addLine(new, config->cfi, LT_KERNEL,
3581          config->primaryIndent,
3582          newKernelPath + strlen(prefix));
3583        needs &= ~NEED_KERNEL;
3584        break;
3585     }
3586    
3587        case LT_HYPER:
3588     newLine = addLine(new, config->cfi, LT_HYPER,
3589      config->primaryIndent,
3590      newMBKernel + strlen(prefix));
3591     needs &= ~NEED_MB;
3592   break;   break;
         }  
3593    
3594   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3595      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3596       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3597       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3598      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3599       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3600      default:        config->primaryIndent, nkt);
3601                  /* zipl strikes again */   free(nkt);
3602                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3603                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3604                      chptr = newKernelTitle;   break;
3605                      type = LT_TITLE;      }
3606                      break;      case LT_TITLE:
3607                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3608                      abort();   char * templabel;
3609                  }   int x = 0, y = 0;
3610   }  
3611     templabel = strdup(newKernelTitle);
3612     while( templabel[x]){
3613     if( templabel[x] == ' ' ){
3614     y = x;
3615     while( templabel[y] ){
3616     templabel[y] = templabel[y+1];
3617     y++;
3618     }
3619     }
3620     x++;
3621     }
3622     newLine = addLine(new, config->cfi, LT_TITLE,
3623      config->primaryIndent, templabel);
3624     free(templabel);
3625     }else{
3626     newLine = addLine(new, config->cfi, LT_TITLE,
3627      config->primaryIndent, newKernelTitle);
3628     }
3629     needs &= ~NEED_TITLE;
3630     break;
3631    
3632   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3633   new->lines = newLine;   abort();
3634     }
3635      }      }
3636    
3637      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3638          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3639              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3640                                config->secondaryIndent,       */
3641                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3642          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3643              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3644                                config->secondaryIndent,    newKernelTitle);
3645                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3646          /* don't need to check for title as it's guaranteed to have been      }
3647           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3648           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3649          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3650              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3651                                config->secondaryIndent,   needs &= ~NEED_MB;
3652                                newKernelInitrd + strlen(prefix));      }
3653      } else {      if (needs & NEED_KERNEL) {
3654          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3655              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3656                                config->secondaryIndent,        config->cfi)) ?
3657                                newKernelPath + strlen(prefix));    LT_MBMODULE : LT_KERNEL,
3658          if (needs & KERNEL_TITLE)    config->secondaryIndent,
3659              newLine = addLine(new, config->cfi, LT_TITLE,    newKernelPath + strlen(prefix));
3660                                config->secondaryIndent,   needs &= ~NEED_KERNEL;
3661                                newKernelTitle);      }
3662          if (needs & KERNEL_INITRD && newKernelInitrd)      if (needs & NEED_MB) {
3663              newLine = addLine(new, config->cfi, LT_INITRD,   newLine = addLine(new, config->cfi, LT_HYPER,
3664                                config->secondaryIndent,    config->secondaryIndent,
3665                                newKernelInitrd + strlen(prefix));    newMBKernel + strlen(prefix));
3666     needs &= ~NEED_MB;
3667        }
3668        if (needs & NEED_INITRD) {
3669     char *initrdVal;
3670     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3671     newLine = addLine(new, config->cfi,
3672      (new->multiboot && getKeywordByType(LT_MBMODULE,
3673          config->cfi)) ?
3674      LT_MBMODULE : LT_INITRD,
3675      config->secondaryIndent,
3676      initrdVal);
3677     free(initrdVal);
3678     needs &= ~NEED_INITRD;
3679        }
3680        if (needs & NEED_END) {
3681     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3682     config->secondaryIndent, NULL);
3683     needs &= ~NEED_END;
3684        }
3685    
3686        if (needs) {
3687     printf(_("grubby: needs=%d, aborting\n"), needs);
3688     abort();
3689      }      }
3690    
3691      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3694  int addNewKernel(struct grubConfig * con
3694      return 0;      return 0;
3695  }  }
3696    
3697    static void traceback(int signum)
3698    {
3699        void *array[40];
3700        size_t size;
3701    
3702        signal(SIGSEGV, SIG_DFL);
3703        memset(array, '\0', sizeof (array));
3704        size = backtrace(array, 40);
3705    
3706        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3707                (unsigned long)size);
3708        backtrace_symbols_fd(array, size, STDERR_FILENO);
3709        exit(1);
3710    }
3711    
3712  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3713      poptContext optCon;      poptContext optCon;
3714      char * grubConfig = NULL;      const char * grubConfig = NULL;
3715      char * outputFile = NULL;      char * outputFile = NULL;
3716      int arg = 0;      int arg = 0;
3717      int flags = 0;      int flags = 0;
3718      int badImageOkay = 0;      int badImageOkay = 0;
3719        int configureGrub2 = 0;
3720      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3721      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3722        int configureExtLinux = 0;
3723      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3724        int extraInitrdCount = 0;
3725      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3726      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3727      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3737  int main(int argc, const char ** argv) {
3737      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3738      char * removeArgs = NULL;      char * removeArgs = NULL;
3739      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3740        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3741      const char * chptr = NULL;      const char * chptr = NULL;
3742      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3743      struct grubConfig * config;      struct grubConfig * config;
3744      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3745      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3746      int displayDefault = 0;      int displayDefault = 0;
3747        int displayDefaultIndex = 0;
3748        int displayDefaultTitle = 0;
3749        int defaultIndex = -1;
3750      struct poptOption options[] = {      struct poptOption options[] = {
3751   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3752      _("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 3764  int main(int argc, const char ** argv) {
3764   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3765      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3766      _("bootfs") },      _("bootfs") },
3767  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3768   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3769      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3770  #endif  #endif
3771   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3772      _("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 3777  int main(int argc, const char ** argv) {
3777        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3778        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3779        "template"), NULL },        "template"), NULL },
3780     { "debug", 0, 0, &debug, 0,
3781        _("print debugging information for failures") },
3782   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3783      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3784     { "default-index", 0, 0, &displayDefaultIndex, 0,
3785        _("display the index of the default kernel") },
3786     { "default-title", 0, 0, &displayDefaultTitle, 0,
3787        _("display the title of the default kernel") },
3788   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3789      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3790     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3791        _("configure extlinux bootloader (from syslinux)") },
3792   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3793      _("configure grub bootloader") },      _("configure grub bootloader") },
3794     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3795        _("configure grub2 bootloader") },
3796   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3797      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3798      _("kernel-path") },      _("kernel-path") },
3799   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3800      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3801     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3802        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3803   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3804      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3805   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3819  int main(int argc, const char ** argv) {
3819   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3820      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3821        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3822     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3823        _("make the given entry index the default entry"),
3824        _("entry-index") },
3825   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3826      _("configure silo bootloader") },      _("configure silo bootloader") },
3827   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3839  int main(int argc, const char ** argv) {
3839   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3840      };      };
3841    
3842        useextlinuxmenu=0;
3843    
3844        signal(SIGSEGV, traceback);
3845    
3846      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3847      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3848    
# Line 2391  int main(int argc, const char ** argv) { Line 3852  int main(int argc, const char ** argv) {
3852      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3853      exit(0);      exit(0);
3854      break;      break;
3855      case 'i':
3856        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3857         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3858        } else {
3859     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3860     return 1;
3861        }
3862        break;
3863   }   }
3864      }      }
3865    
# Line 2406  int main(int argc, const char ** argv) { Line 3875  int main(int argc, const char ** argv) {
3875   return 1;   return 1;
3876      }      }
3877    
3878      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3879   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3880     configureExtLinux ) > 1) {
3881   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3882   return 1;   return 1;
3883      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3884   fprintf(stderr,   fprintf(stderr,
3885      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3886   return 1;   return 1;
3887        } else if (configureGrub2) {
3888     cfi = &grub2ConfigType;
3889      } else if (configureLilo) {      } else if (configureLilo) {
3890   cfi = &liloConfigType;   cfi = &liloConfigType;
3891      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3898  int main(int argc, const char ** argv) {
3898          cfi = &siloConfigType;          cfi = &siloConfigType;
3899      } else if (configureZipl) {      } else if (configureZipl) {
3900          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3901        } else if (configureExtLinux) {
3902     cfi = &extlinuxConfigType;
3903     useextlinuxmenu=1;
3904      }      }
3905    
3906      if (!cfi) {      if (!cfi) {
3907            if (grub2FindConfig(&grub2ConfigType))
3908        cfi = &grub2ConfigType;
3909     else
3910        #ifdef __ia64__        #ifdef __ia64__
3911   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3912        #elif __powerpc__        #elif __powerpc__
3913   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3914        #elif __sparc__        #elif __sparc__
3915          cfi = &siloConfigType;              cfi = &siloConfigType;
3916        #elif __s390__        #elif __s390__
3917          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3918        #elif __s390x__        #elif __s390x__
3919          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3920        #else        #else
3921   cfi = &grubConfigType;      cfi = &grubConfigType;
3922        #endif        #endif
3923      }      }
3924    
3925      if (!grubConfig)      if (!grubConfig) {
3926   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3927        grubConfig = cfi->findConfig(cfi);
3928     if (!grubConfig)
3929        grubConfig = cfi->defaultConfig;
3930        }
3931    
3932      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3933    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
3934    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
3935        (defaultIndex >= 0))) {
3936   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3937    "specified option"));    "specified option"));
3938   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3948  int main(int argc, const char ** argv) {
3948      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3949   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3950   return 1;   return 1;
3951      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3952    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3953    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3954   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
3955   return 1;   return 1;
3956      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 3974  int main(int argc, const char ** argv) {
3974   makeDefault = 1;   makeDefault = 1;
3975   defaultKernel = NULL;   defaultKernel = NULL;
3976      }      }
3977        else if (defaultKernel && (defaultIndex >= 0)) {
3978     fprintf(stderr, _("grubby: --set-default and --set-default-index "
3979      "may not be used together\n"));
3980     return 1;
3981        }
3982    
3983      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
3984   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
3985   "is used\n"));   "is used\n"));
3986   return 1;   return 1;
3987      }      }
3988    
3989      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
3990   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
3991          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
3992     && (defaultIndex == -1)) {
3993   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
3994   return 1;   return 1;
3995      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4009  int main(int argc, const char ** argv) {
4009   bootPrefix = "";   bootPrefix = "";
4010      }      }
4011    
4012        if (!cfi->mbAllowExtraInitRds &&
4013     extraInitrdCount > 0) {
4014     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4015     return 1;
4016        }
4017    
4018      if (bootloaderProbe) {      if (bootloaderProbe) {
4019   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4020   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4021    
4022     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4023     if (grub2config) {
4024        gconfig = readConfig(grub2config, &grub2ConfigType);
4025        if (!gconfig)
4026     gr2c = 1;
4027        else
4028     gr2c = checkForGrub2(gconfig);
4029     }
4030    
4031   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4032      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4033        gconfig = readConfig(grubconfig, &grubConfigType);
4034      if (!gconfig)      if (!gconfig)
4035   grc = 1;   grc = 1;
4036      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4045  int main(int argc, const char ** argv) {
4045   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4046   }   }
4047    
4048   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4049        econfig = readConfig(eliloConfigType.defaultConfig,
4050     &eliloConfigType);
4051        if (!econfig)
4052     erc = 1;
4053        else
4054     erc = checkForElilo(econfig);
4055     }
4056    
4057     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4058        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4059        if (!lconfig)
4060     extrc = 1;
4061        else
4062     extrc = checkForExtLinux(lconfig);
4063     }
4064    
4065    
4066     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4067        yconfig = readConfig(yabootConfigType.defaultConfig,
4068     &yabootConfigType);
4069        if (!yconfig)
4070     yrc = 1;
4071        else
4072     yrc = checkForYaboot(yconfig);
4073     }
4074    
4075     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4076     erc == 1)
4077        return 1;
4078    
4079   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4080     if (gr2c == 2) printf("grub2\n");
4081   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4082     if (extrc == 2) printf("extlinux\n");
4083     if (yrc == 2) printf("yaboot\n");
4084     if (erc == 2) printf("elilo\n");
4085    
4086   return 0;   return 0;
4087      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4099  int main(int argc, const char ** argv) {
4099   if (!entry) return 0;   if (!entry) return 0;
4100   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4101    
4102   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4103   if (!line) return 0;   if (!line) return 0;
4104    
4105          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4107  int main(int argc, const char ** argv) {
4107                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4108    
4109   return 0;   return 0;
4110    
4111        } else if (displayDefaultTitle) {
4112     struct singleLine * line;
4113     struct singleEntry * entry;
4114    
4115     if (config->defaultImage == -1) return 0;
4116     entry = findEntryByIndex(config, config->defaultImage);
4117     if (!entry) return 0;
4118    
4119     if (!configureGrub2) {
4120      line = getLineByType(LT_TITLE, entry->lines);
4121      if (!line) return 0;
4122      printf("%s\n", line->elements[1].item);
4123    
4124     } else {
4125      char * title;
4126    
4127      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4128      line = getLineByType(LT_MENUENTRY, entry->lines);
4129      if (!line) return 0;
4130      title = grub2ExtractTitle(line);
4131      if (title)
4132        printf("%s\n", title);
4133     }
4134     return 0;
4135    
4136        } else if (displayDefaultIndex) {
4137            if (config->defaultImage == -1) return 0;
4138            printf("%i\n", config->defaultImage);
4139    
4140      } else if (kernelInfo)      } else if (kernelInfo)
4141   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4142    
# Line 2581  int main(int argc, const char ** argv) { Line 4148  int main(int argc, const char ** argv) {
4148      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4149      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4150      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4151      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4152      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4153      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4154                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4155        if (updateKernelPath && newKernelInitrd) {
4156                if (updateInitrd(config, updateKernelPath, bootPrefix,
4157                                 newKernelInitrd)) return 1;
4158        }
4159      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4160                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4161                         (const char **)extraInitrds, extraInitrdCount,
4162                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4163            
4164    
# Line 2597  int main(int argc, const char ** argv) { Line 4169  int main(int argc, const char ** argv) {
4169      }      }
4170    
4171      if (!outputFile)      if (!outputFile)
4172   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4173    
4174      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4175  }  }

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