Magellan Linux

Diff of /tags/grubby-8_21/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 1940 by niro, Mon Oct 1 12:39:50 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    int isEfi = 0;
60    
61  /* comments get lumped in with indention */  /* comments get lumped in with indention */
62  struct lineElement {  struct lineElement {
63      char * item;      char * item;
64      char * indent;      char * indent;
65  };  };
66    
67  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
68         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
69         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
70        LT_KERNEL       = 1 << 2,
71        LT_INITRD       = 1 << 3,
72        LT_HYPER        = 1 << 4,
73        LT_DEFAULT      = 1 << 5,
74        LT_MBMODULE     = 1 << 6,
75        LT_ROOT         = 1 << 7,
76        LT_FALLBACK     = 1 << 8,
77        LT_KERNELARGS   = 1 << 9,
78        LT_BOOT         = 1 << 10,
79        LT_BOOTROOT     = 1 << 11,
80        LT_LBA          = 1 << 12,
81        LT_OTHER        = 1 << 13,
82        LT_GENERIC      = 1 << 14,
83        LT_ECHO    = 1 << 16,
84        LT_MENUENTRY    = 1 << 17,
85        LT_ENTRY_END    = 1 << 18,
86        LT_SET_VARIABLE = 1 << 19,
87        LT_KERNEL_EFI   = 1 << 20,
88        LT_INITRD_EFI   = 1 << 21,
89        LT_UNKNOWN      = 1 << 22,
90    };
91    
92  struct singleLine {  struct singleLine {
93      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 108  struct singleEntry {
108    
109  #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 */
110    
111  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
112  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
113  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
114  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
115  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
116    #define NEED_MB      (1 << 4)
117    #define NEED_END     (1 << 5)
118    
119  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
120  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
121    #define DEFAULT_SAVED_GRUB2 -3
122    
123  struct keywordTypes {  struct keywordTypes {
124      char * key;      char * key;
125      enum lineType_e type;      enum lineType_e type;
126      char nextChar;      char nextChar;
127  } ;      char separatorChar;
128    };
129    
130    struct configFileInfo;
131    
132    typedef const char *(*findConfigFunc)(struct configFileInfo *);
133    typedef const int (*writeLineFunc)(struct configFileInfo *,
134     struct singleLine *line);
135    
136  struct configFileInfo {  struct configFileInfo {
137      char * defaultConfig;      char * defaultConfig;
138        findConfigFunc findConfig;
139        writeLineFunc writeLine;
140      struct keywordTypes * keywords;      struct keywordTypes * keywords;
141      int defaultIsIndex;      int defaultIsIndex;
142        int defaultIsVariable;
143      int defaultSupportSaved;      int defaultSupportSaved;
144      enum lineType_e entrySeparator;      enum lineType_e entryStart;
145        enum lineType_e entryEnd;
146      int needsBootPrefix;      int needsBootPrefix;
147      int argsInQuotes;      int argsInQuotes;
148      int maxTitleLength;      int maxTitleLength;
149      int titleBracketed;      int titleBracketed;
150        int titlePosition;
151        int mbHyperFirst;
152        int mbInitRdIsModule;
153        int mbConcatArgs;
154        int mbAllowExtraInitRds;
155  };  };
156    
157  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 160  struct keywordTypes grubKeywords[] = {
160      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
161      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
162      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
163      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
164      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
165        { "kernel",     LT_HYPER,       ' ' },
166      { NULL,    0, 0 },      { NULL,    0, 0 },
167  };  };
168    
169    const char *grubFindConfig(struct configFileInfo *cfi) {
170        static const char *configFiles[] = {
171     "/boot/grub/grub.conf",
172     "/boot/grub/menu.lst",
173     "/etc/grub.conf",
174     NULL
175        };
176        static int i = -1;
177    
178        if (i == -1) {
179     for (i = 0; configFiles[i] != NULL; i++) {
180        dbgPrintf("Checking \"%s\": ", configFiles[i]);
181        if (!access(configFiles[i], R_OK)) {
182     dbgPrintf("found\n");
183     return configFiles[i];
184        }
185        dbgPrintf("not found\n");
186     }
187        }
188        return configFiles[i];
189    }
190    
191  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
192      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
193      grubKeywords,    /* keywords */      .keywords = grubKeywords,
194      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
195      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
196      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
197      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
198      0,    /* argsInQuotes */      .mbHyperFirst = 1,
199      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
200      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
201    };
202    
203    struct keywordTypes grub2Keywords[] = {
204        { "menuentry",  LT_MENUENTRY,   ' ' },
205        { "}",          LT_ENTRY_END,   ' ' },
206        { "echo",       LT_ECHO,        ' ' },
207        { "set",        LT_SET_VARIABLE,' ', '=' },
208        { "root",       LT_BOOTROOT,    ' ' },
209        { "default",    LT_DEFAULT,     ' ' },
210        { "fallback",   LT_FALLBACK,    ' ' },
211        { "linux",      LT_KERNEL,      ' ' },
212        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
213        { "initrd",     LT_INITRD,      ' ', ' ' },
214        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
215        { "module",     LT_MBMODULE,    ' ' },
216        { "kernel",     LT_HYPER,       ' ' },
217        { NULL, 0, 0 },
218    };
219    
220    const char *grub2FindConfig(struct configFileInfo *cfi) {
221        static const char *configFiles[] = {
222     "/boot/grub/grub-efi.cfg",
223     "/boot/grub/grub.cfg",
224     NULL
225        };
226        static int i = -1;
227        static const char *grub_cfg = "/boot/grub/grub.cfg";
228    
229        if (i == -1) {
230     for (i = 0; configFiles[i] != NULL; i++) {
231        dbgPrintf("Checking \"%s\": ", configFiles[i]);
232        if (!access(configFiles[i], R_OK)) {
233     dbgPrintf("found\n");
234     return configFiles[i];
235        }
236     }
237        }
238    
239        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
240         * that isn't in grub1, and if it exists, return the config file path
241         * that they use. */
242        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
243     dbgPrintf("found\n");
244     return grub_cfg;
245        }
246    
247        dbgPrintf("not found\n");
248        return configFiles[i];
249    }
250    
251    int sizeOfSingleLine(struct singleLine * line) {
252      int count = 0;
253    
254      for (int i = 0; i < line->numElements; i++) {
255        int indentSize = 0;
256    
257        count = count + strlen(line->elements[i].item);
258    
259        indentSize = strlen(line->elements[i].indent);
260        if (indentSize > 0)
261          count = count + indentSize;
262        else
263          /* be extra safe and add room for whitespaces */
264          count = count + 1;
265      }
266    
267      /* room for trailing terminator */
268      count = count + 1;
269    
270      return count;
271    }
272    
273    static int isquote(char q)
274    {
275        if (q == '\'' || q == '\"')
276     return 1;
277        return 0;
278    }
279    
280    static int iskernel(enum lineType_e type) {
281        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
282    }
283    
284    static int isinitrd(enum lineType_e type) {
285        return (type == LT_INITRD || type == LT_INITRD_EFI);
286    }
287    
288    char *grub2ExtractTitle(struct singleLine * line) {
289        char * current;
290        char * current_indent;
291        int current_len;
292        int current_indent_len;
293        int i;
294    
295        /* bail out if line does not start with menuentry */
296        if (strcmp(line->elements[0].item, "menuentry"))
297          return NULL;
298    
299        i = 1;
300        current = line->elements[i].item;
301        current_len = strlen(current);
302    
303        /* if second word is quoted, strip the quotes and return single word */
304        if (isquote(*current) && isquote(current[current_len - 1])) {
305     char *tmp;
306    
307     tmp = strdup(current);
308     *(tmp + current_len - 1) = '\0';
309     return ++tmp;
310        }
311    
312        /* if no quotes, return second word verbatim */
313        if (!isquote(*current))
314     return current;
315    
316        /* second element start with a quote, so we have to find the element
317         * whose last character is also quote (assuming it's the closing one) */
318        int resultMaxSize;
319        char * result;
320        
321        resultMaxSize = sizeOfSingleLine(line);
322        result = malloc(resultMaxSize);
323        snprintf(result, resultMaxSize, "%s", ++current);
324        
325        i++;
326        for (; i < line->numElements; ++i) {
327     current = line->elements[i].item;
328     current_len = strlen(current);
329     current_indent = line->elements[i].indent;
330     current_indent_len = strlen(current_indent);
331    
332     strncat(result, current_indent, current_indent_len);
333     if (!isquote(current[current_len-1])) {
334        strncat(result, current, current_len);
335     } else {
336        strncat(result, current, current_len - 1);
337        break;
338     }
339        }
340        return result;
341    }
342    
343    struct configFileInfo grub2ConfigType = {
344        .findConfig = grub2FindConfig,
345        .keywords = grub2Keywords,
346        .defaultIsIndex = 1,
347        .defaultSupportSaved = 1,
348        .defaultIsVariable = 1,
349        .entryStart = LT_MENUENTRY,
350        .entryEnd = LT_ENTRY_END,
351        .titlePosition = 1,
352        .needsBootPrefix = 1,
353        .mbHyperFirst = 1,
354        .mbInitRdIsModule = 1,
355        .mbAllowExtraInitRds = 1,
356  };  };
357    
358  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 386  struct keywordTypes yabootKeywords[] = {
386      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
387      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
388      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
389      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
390      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
391      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
392      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 406  struct keywordTypes liloKeywords[] = {
406      { NULL,    0, 0 },      { NULL,    0, 0 },
407  };  };
408    
409    struct keywordTypes eliloKeywords[] = {
410        { "label",    LT_TITLE,    '=' },
411        { "root",    LT_ROOT,    '=' },
412        { "default",    LT_DEFAULT,    '=' },
413        { "image",    LT_KERNEL,    '=' },
414        { "initrd",    LT_INITRD,    '=' },
415        { "append",    LT_KERNELARGS,  '=' },
416        { "vmm",    LT_HYPER,       '=' },
417        { NULL,    0, 0 },
418    };
419    
420  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
421      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
422      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 438  struct keywordTypes ziplKeywords[] = {
438      { NULL,         0, 0 },      { NULL,         0, 0 },
439  };  };
440    
441    struct keywordTypes extlinuxKeywords[] = {
442        { "label",    LT_TITLE,    ' ' },
443        { "root",    LT_ROOT,    ' ' },
444        { "default",    LT_DEFAULT,    ' ' },
445        { "kernel",    LT_KERNEL,    ' ' },
446        { "initrd",    LT_INITRD,      ' ', ',' },
447        { "append",    LT_KERNELARGS,  ' ' },
448        { "prompt",     LT_UNKNOWN,     ' ' },
449        { NULL,    0, 0 },
450    };
451    int useextlinuxmenu;
452  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
453      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
454      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
455      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
456      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
457      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
458      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
459  };  };
460    
461  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
462      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
463      liloKeywords,    /* keywords */      .keywords = liloKeywords,
464      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
465      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
466      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
467  };  };
468    
469  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
470      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
471      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
472      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
473      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
474      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
475      1,    /* needsBootPrefix */      .maxTitleLength = 15,
476      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
477  };  };
478    
479  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
480      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
481      siloKeywords,    /* keywords */      .keywords = siloKeywords,
482      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
483      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
484      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
485      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
486  };  };
487    
488  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
489      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
490      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
491      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
492      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
493      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
494      0,    /* needsBootPrefix */  };
495      1,    /* argsInQuotes */  
496      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
497      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
498        .keywords = extlinuxKeywords,
499        .entryStart = LT_TITLE,
500        .needsBootPrefix = 1,
501        .maxTitleLength = 255,
502        .mbAllowExtraInitRds = 1,
503  };  };
504    
505  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 514  struct grubConfig {
514      struct configFileInfo * cfi;      struct configFileInfo * cfi;
515  };  };
516    
517    blkid_cache blkid;
518    
519  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
520  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
521       const char * path, const char * prefix,       const char * path, const char * prefix,
522       int * index);       int * index);
 static char * strndup(char * from, int len);  
523  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
524  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
525    struct singleLine * lineDup(struct singleLine * line);
526  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
527  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
528       struct configFileInfo * cfi);       struct configFileInfo * cfi);
529  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
530         struct configFileInfo * cfi);         struct configFileInfo * cfi);
531  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
532    static void requote(struct singleLine *line, struct configFileInfo * cfi);
533  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
534      char * to;    const char * item, int insertHere,
535      struct configFileInfo * cfi);
536      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
537      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
538      to[len] = '\0';        struct configFileInfo * cfi);
539    static enum lineType_e getTypeByKeyword(char * keyword,
540      return to;   struct configFileInfo * cfi);
541  }  static struct singleLine * getLineByType(enum lineType_e type,
542     struct singleLine * line);
543    static int checkForExtLinux(struct grubConfig * config);
544    struct singleLine * addLineTmpl(struct singleEntry * entry,
545                                    struct singleLine * tmplLine,
546                                    struct singleLine * prevLine,
547                                    const char * val,
548     struct configFileInfo * cfi);
549    struct singleLine *  addLine(struct singleEntry * entry,
550                                 struct configFileInfo * cfi,
551                                 enum lineType_e type, char * defaultIndent,
552                                 const char * val);
553    
554  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
555  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 584  static char * sdupprintf(const char *for
584      return buf;      return buf;
585  }  }
586    
587    static enum lineType_e preferredLineType(enum lineType_e type,
588     struct configFileInfo *cfi) {
589        if (isEfi && cfi == &grub2ConfigType) {
590     switch (type) {
591     case LT_KERNEL:
592        return LT_KERNEL_EFI;
593     case LT_INITRD:
594        return LT_INITRD_EFI;
595     default:
596        return type;
597     }
598        }
599        return type;
600    }
601    
602    static struct keywordTypes * getKeywordByType(enum lineType_e type,
603          struct configFileInfo * cfi) {
604        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
605     if (kw->type == type)
606        return kw;
607        }
608        return NULL;
609    }
610    
611    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
612        struct keywordTypes *kt = getKeywordByType(type, cfi);
613        if (kt)
614     return kt->key;
615        return "unknown";
616    }
617    
618    static char * getpathbyspec(char *device) {
619        if (!blkid)
620            blkid_get_cache(&blkid, NULL);
621    
622        return blkid_get_devname(blkid, device, NULL);
623    }
624    
625    static char * getuuidbydev(char *device) {
626        if (!blkid)
627     blkid_get_cache(&blkid, NULL);
628    
629        return blkid_get_tag_value(blkid, "UUID", device);
630    }
631    
632    static enum lineType_e getTypeByKeyword(char * keyword,
633     struct configFileInfo * cfi) {
634        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
635     if (!strcmp(keyword, kw->key))
636        return kw->type;
637        }
638        return LT_UNKNOWN;
639    }
640    
641    static struct singleLine * getLineByType(enum lineType_e type,
642     struct singleLine * line) {
643        dbgPrintf("getLineByType(%d): ", type);
644        for (; line; line = line->next) {
645     dbgPrintf("%d:%s ", line->type,
646      line->numElements ? line->elements[0].item : "(empty)");
647     if (line->type & type) break;
648        }
649        dbgPrintf(line ? "\n" : " (failed)\n");
650        return line;
651    }
652    
653  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
654      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
655          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
656          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
657              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 663  static int isBracketedTitle(struct singl
663      return 0;      return 0;
664  }  }
665    
666  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
667                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
668      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
669   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;  
670  }  }
671    
672  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 717  static void lineInit(struct singleLine *
717      line->next = NULL;      line->next = NULL;
718  }  }
719    
720  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
721      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
722    
723        newLine->indent = strdup(line->indent);
724        newLine->next = NULL;
725        newLine->type = line->type;
726        newLine->numElements = line->numElements;
727        newLine->elements = malloc(sizeof(*newLine->elements) *
728           newLine->numElements);
729    
730        for (int i = 0; i < newLine->numElements; i++) {
731     newLine->elements[i].indent = strdup(line->elements[i].indent);
732     newLine->elements[i].item = strdup(line->elements[i].item);
733        }
734    
735        return newLine;
736    }
737    
738    static void lineFree(struct singleLine * line) {
739      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
740    
741      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
742   free(line->elements[i].item);   free(line->elements[i].item);
743   free(line->elements[i].indent);   free(line->elements[i].indent);
744      }      }
# Line 405  static void lineFree(struct singleLine * Line 749  static void lineFree(struct singleLine *
749    
750  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
751       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
752      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
753    
754      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
755     /* Need to handle this, because we strip the quotes from
756     * menuentry when read it. */
757     if (line->type == LT_MENUENTRY && i == 1) {
758        if(!isquote(*line->elements[i].item))
759     fprintf(out, "\'%s\'", line->elements[i].item);
760        else
761     fprintf(out, "%s", line->elements[i].item);
762        fprintf(out, "%s", line->elements[i].indent);
763    
764        continue;
765     }
766    
767   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
768      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
769    
770   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
771   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
772        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
773      }      }
774    
775      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 788  static int getNextLine(char ** bufPtr, s
788      char * chptr;      char * chptr;
789      int elementsAlloced = 0;      int elementsAlloced = 0;
790      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
791      int first = 1;      int first = 1;
     int i;  
792    
793      lineFree(line);      lineFree(line);
794    
# Line 489  static int getNextLine(char ** bufPtr, s Line 842  static int getNextLine(char ** bufPtr, s
842      if (!line->numElements)      if (!line->numElements)
843   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
844      else {      else {
845   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
846      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;  
               
847              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
848               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
849              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 857  static int getNextLine(char ** bufPtr, s
857      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
858   char * fullLine;   char * fullLine;
859   int len;   int len;
  int i;  
860    
861   len = strlen(line->indent);   len = strlen(line->indent);
862   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
863      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
864     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
865    
# Line 522  static int getNextLine(char ** bufPtr, s Line 868  static int getNextLine(char ** bufPtr, s
868   free(line->indent);   free(line->indent);
869   line->indent = fullLine;   line->indent = fullLine;
870    
871   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
872      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
873      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
874      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 878  static int getNextLine(char ** bufPtr, s
878   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
879   line->numElements = 0;   line->numElements = 0;
880      }      }
881     } else {
882     struct keywordTypes *kw;
883    
884     kw = getKeywordByType(line->type, cfi);
885    
886     /* space isn't the only separator, we need to split
887     * elements up more
888     */
889     if (!isspace(kw->separatorChar)) {
890        char indent[2] = "";
891        indent[0] = kw->separatorChar;
892        for (int i = 1; i < line->numElements; i++) {
893     char *p;
894     int numNewElements;
895    
896     numNewElements = 0;
897     p = line->elements[i].item;
898     while (*p != '\0') {
899     if (*p == kw->separatorChar)
900     numNewElements++;
901     p++;
902     }
903     if (line->numElements + numNewElements >= elementsAlloced) {
904     elementsAlloced += numNewElements + 5;
905     line->elements = realloc(line->elements,
906        sizeof(*line->elements) * elementsAlloced);
907     }
908    
909     for (int j = line->numElements; j > i; j--) {
910     line->elements[j + numNewElements] = line->elements[j];
911     }
912     line->numElements += numNewElements;
913    
914     p = line->elements[i].item;
915     while (*p != '\0') {
916    
917     while (*p != kw->separatorChar && *p != '\0') p++;
918     if (*p == '\0') {
919     break;
920     }
921    
922     line->elements[i + 1].indent = line->elements[i].indent;
923     line->elements[i].indent = strdup(indent);
924     *p++ = '\0';
925     i++;
926     line->elements[i].item = strdup(p);
927     }
928        }
929     }
930   }   }
931      }      }
932    
# Line 549  static struct grubConfig * readConfig(co Line 944  static struct grubConfig * readConfig(co
944      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
945      char * end;      char * end;
946      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
947      int i, len;      int len;
948      char * buf;      char * buf;
949    
950      if (!strcmp(inName, "-")) {      if (!strcmp(inName, "-")) {
# Line 595  static struct grubConfig * readConfig(co Line 990  static struct grubConfig * readConfig(co
990      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
991   }   }
992    
993   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
994      sawEntry = 1;      sawEntry = 1;
995      if (!entry) {      if (!entry) {
996   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1006  static struct grubConfig * readConfig(co
1006      entry->next = NULL;      entry->next = NULL;
1007   }   }
1008    
1009   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1010        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1011        dbgPrintf("%s", line->indent);
1012        for (int i = 0; i < line->numElements; i++)
1013     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1014        dbgPrintf("\n");
1015        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1016        if (kwType && line->numElements == 3 &&
1017        !strcmp(line->elements[1].item, kwType->key)) {
1018     dbgPrintf("Line sets default config\n");
1019     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1020     defaultLine = line;
1021        }
1022     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1023      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1024      defaultLine = line;      defaultLine = line;
1025    
1026            } else if (iskernel(line->type)) {
1027        /* if by some freak chance this is multiboot and the "module"
1028         * lines came earlier in the template, make sure to use LT_HYPER
1029         * instead of LT_KERNEL now
1030         */
1031        if (entry->multiboot)
1032     line->type = LT_HYPER;
1033    
1034          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1035        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1036         * instead, now that we know this is a multiboot entry.
1037         * This only applies to grub, but that's the only place we
1038         * should find LT_MBMODULE lines anyway.
1039         */
1040        for (struct singleLine *l = entry->lines; l; l = l->next) {
1041     if (l->type == LT_HYPER)
1042        break;
1043     else if (iskernel(l->type)) {
1044        l->type = LT_HYPER;
1045        break;
1046     }
1047        }
1048              entry->multiboot = 1;              entry->multiboot = 1;
1049    
1050     } else if (line->type == LT_HYPER) {
1051        entry->multiboot = 1;
1052    
1053   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1054      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1055      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1056    
1057   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1058      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1059      len = 0;      len = 0;
1060      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1061   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1062   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1063      }      }
1064      buf = malloc(len + 1);      buf = malloc(len + 1);
1065      *buf = '\0';      *buf = '\0';
1066    
1067      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1068   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1069   free(line->elements[i].item);   free(line->elements[i].item);
1070    
# Line 643  static struct grubConfig * readConfig(co Line 1078  static struct grubConfig * readConfig(co
1078      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1079      line->elements[1].item = buf;      line->elements[1].item = buf;
1080      line->numElements = 2;      line->numElements = 2;
1081     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1082        /* let --remove-kernel="TITLE=what" work */
1083        len = 0;
1084        char *extras;
1085        char *title;
1086    
1087        for (int i = 1; i < line->numElements; i++) {
1088     len += strlen(line->elements[i].item);
1089     len += strlen(line->elements[i].indent);
1090        }
1091        buf = malloc(len + 1);
1092        *buf = '\0';
1093    
1094        /* allocate mem for extra flags. */
1095        extras = malloc(len + 1);
1096        *extras = '\0';
1097    
1098        /* get title. */
1099        for (int i = 0; i < line->numElements; i++) {
1100     if (!strcmp(line->elements[i].item, "menuentry"))
1101        continue;
1102     if (isquote(*line->elements[i].item))
1103        title = line->elements[i].item + 1;
1104     else
1105        title = line->elements[i].item;
1106    
1107     len = strlen(title);
1108            if (isquote(title[len-1])) {
1109        strncat(buf, title,len-1);
1110        break;
1111     } else {
1112        strcat(buf, title);
1113        strcat(buf, line->elements[i].indent);
1114     }
1115        }
1116    
1117        /* get extras */
1118        int count = 0;
1119        for (int i = 0; i < line->numElements; i++) {
1120     if (count >= 2) {
1121        strcat(extras, line->elements[i].item);
1122        strcat(extras, line->elements[i].indent);
1123     }
1124    
1125     if (!strcmp(line->elements[i].item, "menuentry"))
1126        continue;
1127    
1128     /* count ' or ", there should be two in menuentry line. */
1129     if (isquote(*line->elements[i].item))
1130        count++;
1131    
1132     len = strlen(line->elements[i].item);
1133    
1134     if (isquote(line->elements[i].item[len -1]))
1135        count++;
1136    
1137     /* ok, we get the final ' or ", others are extras. */
1138                }
1139        line->elements[1].indent =
1140     line->elements[line->numElements - 2].indent;
1141        line->elements[1].item = buf;
1142        line->elements[2].indent =
1143     line->elements[line->numElements - 2].indent;
1144        line->elements[2].item = extras;
1145        line->numElements = 3;
1146   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1147      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1148         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 1151  static struct grubConfig * readConfig(co
1151      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1152   int last, len;   int last, len;
1153    
1154   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1155      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1156     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1157    
1158   last = line->numElements - 1;   last = line->numElements - 1;
1159   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1160   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1161      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1162      }      }
   
1163   }   }
1164    
1165   /* 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 1179  static struct grubConfig * readConfig(co
1179   movedLine = 1;   movedLine = 1;
1180   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1181   }   }
1182    
1183   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1184     which was moved, drop it. */     which was moved, drop it. */
1185   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 1195  static struct grubConfig * readConfig(co
1195   entry->lines = line;   entry->lines = line;
1196      else      else
1197   last->next = line;   last->next = line;
1198        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1199    
1200        /* we could have seen this outside of an entry... if so, we
1201         * ignore it like any other line we don't grok */
1202        if (line->type == LT_ENTRY_END && sawEntry)
1203     sawEntry = 0;
1204   } else {   } else {
1205      if (!cfg->theLines)      if (!cfg->theLines)
1206   cfg->theLines = line;   cfg->theLines = line;
1207      else {      else
1208   last->next = line;   last->next = line;
1209      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1210   }   }
1211    
1212   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1214  static struct grubConfig * readConfig(co
1214    
1215      free(incoming);      free(incoming);
1216    
1217        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1218      if (defaultLine) {      if (defaultLine) {
1219   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1220        cfi->defaultSupportSaved &&
1221        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1222        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1223     } else if (cfi->defaultIsVariable) {
1224        char *value = defaultLine->elements[2].item;
1225        while (*value && (*value == '"' || *value == '\'' ||
1226        *value == ' ' || *value == '\t'))
1227     value++;
1228        cfg->defaultImage = strtol(value, &end, 10);
1229        while (*end && (*end == '"' || *end == '\'' ||
1230        *end == ' ' || *end == '\t'))
1231     end++;
1232        if (*end) cfg->defaultImage = -1;
1233     } else if (cfi->defaultSupportSaved &&
1234   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1235      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1236   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1237      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1238      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1239   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1240      i = 0;      int i = 0;
1241      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1242   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1243      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1251  static struct grubConfig * readConfig(co
1251                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1252                  }                  }
1253   i++;   i++;
1254     entry = NULL;
1255      }      }
1256    
1257      if (entry) cfg->defaultImage = i;      if (entry){
1258            cfg->defaultImage = i;
1259        }else{
1260            cfg->defaultImage = -1;
1261        }
1262   }   }
1263        } else {
1264            cfg->defaultImage = 0;
1265      }      }
1266    
1267      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1277  static void writeDefault(FILE * out, cha
1277    
1278      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1279   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1280        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1281     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1282      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1283   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1284      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1285      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1286     cfg->defaultImage);
1287        } else {
1288     fprintf(out, "%sdefault%s%d\n", indent, separator,
1289     cfg->defaultImage);
1290        }
1291   } else {   } else {
1292      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1293    
# Line 769  static void writeDefault(FILE * out, cha Line 1304  static void writeDefault(FILE * out, cha
1304    
1305      if (!entry) return;      if (!entry) return;
1306    
1307      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1308    
1309      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1310   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1338  static int writeConfig(struct grubConfig
1338      int rc;      int rc;
1339    
1340      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1341         directory to / */         directory to the dir of the symlink */
1342      rc = chdir("/");      char *dir = strdupa(outName);
1343        rc = chdir(dirname(dir));
1344      do {      do {
1345   buf = alloca(len + 1);   buf = alloca(len + 1);
1346   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1347   if (rc == len) len += 256;   if (rc == len) len += 256;
1348      } while (rc == len);      } while (rc == len);
1349            
# Line 843  static int writeConfig(struct grubConfig Line 1378  static int writeConfig(struct grubConfig
1378      }      }
1379    
1380      line = cfg->theLines;      line = cfg->theLines;
1381        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1382      while (line) {      while (line) {
1383   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1384     line->numElements == 3 &&
1385     !strcmp(line->elements[1].item, defaultKw->key)) {
1386        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1387        needs &= ~MAIN_DEFAULT;
1388     } else if (line->type == LT_DEFAULT) {
1389      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1390      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1391   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1453  static int numEntries(struct grubConfig
1453      return i;      return i;
1454  }  }
1455    
1456    static char *findDiskForRoot()
1457    {
1458        int fd;
1459        char buf[65536];
1460        char *devname;
1461        char *chptr;
1462        int rc;
1463    
1464        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1465            fprintf(stderr, "grubby: failed to open %s: %s\n",
1466                    _PATH_MOUNTED, strerror(errno));
1467            return NULL;
1468        }
1469    
1470        rc = read(fd, buf, sizeof(buf) - 1);
1471        if (rc <= 0) {
1472            fprintf(stderr, "grubby: failed to read %s: %s\n",
1473                    _PATH_MOUNTED, strerror(errno));
1474            close(fd);
1475            return NULL;
1476        }
1477        close(fd);
1478        buf[rc] = '\0';
1479        chptr = buf;
1480    
1481        char *foundanswer = NULL;
1482    
1483        while (chptr && chptr != buf+rc) {
1484            devname = chptr;
1485    
1486            /*
1487             * The first column of a mtab entry is the device, but if the entry is a
1488             * special device it won't start with /, so move on to the next line.
1489             */
1490            if (*devname != '/') {
1491                chptr = strchr(chptr, '\n');
1492                if (chptr)
1493                    chptr++;
1494                continue;
1495            }
1496    
1497            /* Seek to the next space */
1498            chptr = strchr(chptr, ' ');
1499            if (!chptr) {
1500                fprintf(stderr, "grubby: error parsing %s: %s\n",
1501                        _PATH_MOUNTED, strerror(errno));
1502                return NULL;
1503            }
1504    
1505            /*
1506             * The second column of a mtab entry is the mount point, we are looking
1507             * for '/' obviously.
1508             */
1509            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1510                /* remember the last / entry in mtab */
1511               foundanswer = devname;
1512            }
1513    
1514            /* Next line */
1515            chptr = strchr(chptr, '\n');
1516            if (chptr)
1517                chptr++;
1518        }
1519    
1520        /* Return the last / entry found */
1521        if (foundanswer) {
1522            chptr = strchr(foundanswer, ' ');
1523            *chptr = '\0';
1524            return strdup(foundanswer);
1525        }
1526    
1527        return NULL;
1528    }
1529    
1530    void printEntry(struct singleEntry * entry) {
1531        int i;
1532        struct singleLine * line;
1533    
1534        for (line = entry->lines; line; line = line->next) {
1535     fprintf(stderr, "DBG: %s", line->indent);
1536     for (i = 0; i < line->numElements; i++) {
1537        /* Need to handle this, because we strip the quotes from
1538         * menuentry when read it. */
1539        if (line->type == LT_MENUENTRY && i == 1) {
1540     if(!isquote(*line->elements[i].item))
1541        fprintf(stderr, "\'%s\'", line->elements[i].item);
1542     else
1543        fprintf(stderr, "%s", line->elements[i].item);
1544     fprintf(stderr, "%s", line->elements[i].indent);
1545    
1546     continue;
1547        }
1548        
1549        fprintf(stderr, "%s%s",
1550        line->elements[i].item, line->elements[i].indent);
1551     }
1552     fprintf(stderr, "\n");
1553        }
1554    }
1555    
1556    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1557    {
1558        va_list argp;
1559    
1560        if (!debug)
1561     return;
1562    
1563        va_start(argp, fmt);
1564        fprintf(stderr, "DBG: Image entry failed: ");
1565        vfprintf(stderr, fmt, argp);
1566        printEntry(entry);
1567        va_end(argp);
1568    }
1569    
1570    #define beginswith(s, c) ((s) && (s)[0] == (c))
1571    
1572    static int endswith(const char *s, char c)
1573    {
1574     int slen;
1575    
1576     if (!s || !s[0])
1577     return 0;
1578     slen = strlen(s) - 1;
1579    
1580     return s[slen] == c;
1581    }
1582    
1583  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1584    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1585      struct singleLine * line;      struct singleLine * line;
1586      char * fullName;      char * fullName;
1587      int i;      int i;
     struct stat sb, sb2;  
1588      char * dev;      char * dev;
     char * end;  
1589      char * rootspec;      char * rootspec;
1590        char * rootdev;
1591    
1592      line = entry->lines;      if (skipRemoved && entry->skip) {
1593      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1594         return 0;
1595      if (!line) return 0;      }
1596      if (skipRemoved && entry->skip) return 0;  
1597      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1598        if (!line) {
1599     notSuitablePrintf(entry, "no line found\n");
1600     return 0;
1601        }
1602        if (line->numElements < 2) {
1603     notSuitablePrintf(entry, "line has only %d elements\n",
1604        line->numElements);
1605     return 0;
1606        }
1607    
1608      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1609    
1610      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1611        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1612      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1613      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1614              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1615                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1616      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1617                line->elements[1].item + rootspec_offset);
1618        if (access(fullName, R_OK)) {
1619     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1620     return 0;
1621        }
1622      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1623   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1624      if (i < line->numElements) {      if (i < line->numElements) {
1625   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1626      } else {      } else {
1627   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1628   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1629    
1630   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1631      dev = line->elements[1].item;      dev = line->elements[1].item;
1632   } else {   } else {
1633              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1634      /* 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.
1635      line = entry->lines;       */
1636        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1637    
1638              /* failed to find one */              /* failed to find one */
1639              if (!line) return 0;              if (!line) {
1640     notSuitablePrintf(entry, "no line found\n");
1641     return 0;
1642                }
1643    
1644      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1645          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1646      if (i < line->numElements)      if (i < line->numElements)
1647          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1648      else {      else {
1649     notSuitablePrintf(entry, "no root= entry found\n");
1650   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1651          return 0;          return 0;
1652              }              }
1653   }   }
1654      }      }
1655    
1656      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1657   dev += 6;      if (!getpathbyspec(dev)) {
1658            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1659   /* check which device has this label */          return 0;
1660   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1661   if (!dev) return 0;   dev = getpathbyspec(dev);
1662    
1663        rootdev = findDiskForRoot();
1664        if (!rootdev) {
1665            notSuitablePrintf(entry, "can't find root device\n");
1666     return 0;
1667      }      }
1668    
1669      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1670   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1671      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1672      } else {          free(rootdev);
1673   sb.st_rdev = strtol(dev, &end, 16);          return 0;
  if (*end) return 0;  
1674      }      }
     stat("/", &sb2);  
1675    
1676      if (sb.st_rdev != sb2.st_dev) return 0;      if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1677            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1678     getuuidbydev(rootdev), getuuidbydev(dev));
1679     free(rootdev);
1680            return 0;
1681        }
1682    
1683        free(rootdev);
1684    
1685      return 1;      return 1;
1686  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1724  struct singleEntry * findEntryByPath(str
1724   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1725   if (!entry) return NULL;   if (!entry) return NULL;
1726    
1727   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1728   if (!line) return NULL;   if (!line) return NULL;
1729    
1730   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1762  struct singleEntry * findEntryByPath(str
1762    
1763   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1764      prefix = "";      prefix = "";
1765      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1766      kernel += 6;      kernel += 6;
1767   }   }
1768    
1769   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1770      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1771    
1772        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1773    
1774      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1775                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1776          if (!strcmp(line->elements[1].item  +   line = getLineByType(entry->multiboot && checkType == LT_KERNEL
1777                              ((rootspec != NULL) ? strlen(rootspec) : 0),   ? LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER
1778                              kernel + strlen(prefix)))   : checkType, line);
1779                      break;   if (!line) break;  /* not found in this entry */
1780              }  
1781                 if (line && line->type != LT_MENUENTRY &&
1782              /* have to check multiboot lines too */   line->numElements >= 2) {
1783              if (entry->multiboot) {      rootspec = getRootSpecifier(line->elements[1].item);
1784                  while (line && line->type != LT_MBMODULE) line = line->next;      if (!strcmp(line->elements[1].item +
1785                  if (line && line->numElements >= 2 && !entry->skip) {   ((rootspec != NULL) ? strlen(rootspec) : 0),
1786                      rootspec = getRootSpecifier(line->elements[1].item);   kernel + strlen(prefix)))
1787                      if (!strcmp(line->elements[1].item  +   break;
1788                                  ((rootspec != NULL) ? strlen(rootspec) : 0),   }
1789                                  kernel + strlen(prefix)))   if(line->type == LT_MENUENTRY &&
1790                          break;   !strcmp(line->elements[1].item, kernel))
1791                  }      break;
1792              }      }
1793    
1794      i++;      /* make sure this entry has a kernel identifier; this skips
1795         * non-Linux boot entries (could find netbsd etc, though, which is
1796         * unfortunate)
1797         */
1798        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1799     break; /* found 'im! */
1800   }   }
1801    
1802   if (index) *index = i;   if (index) *index = i;
1803      }      }
1804    
     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);  
     }  
   
1805      return entry;      return entry;
1806  }  }
1807    
# Line 1200  void markRemovedImage(struct grubConfig Line 1880  void markRemovedImage(struct grubConfig
1880        const char * prefix) {        const char * prefix) {
1881      struct singleEntry * entry;      struct singleEntry * entry;
1882    
1883      if (!image) return;      if (!image)
1884     return;
1885    
1886        /* check and see if we're removing the default image */
1887        if (isdigit(*image)) {
1888     entry = findEntryByPath(cfg, image, prefix, NULL);
1889     if(entry)
1890        entry->skip = 1;
1891     return;
1892        }
1893    
1894      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1895   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1897  void markRemovedImage(struct grubConfig
1897    
1898  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1899       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1900       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1901      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1902      int i, j;      int i, j;
1903    
1904      if (newIsDefault) {      if (newIsDefault) {
1905   config->defaultImage = 0;   config->defaultImage = 0;
1906   return;   return;
1907        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1908     if (findEntryByIndex(config, index))
1909        config->defaultImage = index;
1910     else
1911        config->defaultImage = -1;
1912     return;
1913      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1914   i = 0;   i = 0;
1915   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1922  void setDefaultImage(struct grubConfig *
1922    
1923      /* 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
1924         changes */         changes */
1925      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1926     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1927        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1928        return;        return;
1929    
# Line 1286  void displayEntry(struct singleEntry * e Line 1982  void displayEntry(struct singleEntry * e
1982      char * root = NULL;      char * root = NULL;
1983      int i;      int i;
1984    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1985      printf("index=%d\n", index);      printf("index=%d\n", index);
1986    
1987      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1988        if (!line) {
1989            printf("non linux entry\n");
1990            return;
1991        }
1992    
1993        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
1994     printf("kernel=%s\n", line->elements[1].item);
1995        else
1996     printf("kernel=%s%s\n", prefix, line->elements[1].item);
1997    
1998      if (line->numElements >= 3) {      if (line->numElements >= 3) {
1999   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2010  void displayEntry(struct singleEntry * e
2010   }   }
2011   printf("\"\n");   printf("\"\n");
2012      } else {      } else {
2013   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2014   if (line) {   if (line) {
2015      char * s;      char * s;
2016    
# Line 1334  void displayEntry(struct singleEntry * e Line 2034  void displayEntry(struct singleEntry * e
2034      }      }
2035    
2036      if (!root) {      if (!root) {
2037   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2038   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2039      root=line->elements[1].item;      root=line->elements[1].item;
2040      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2049  void displayEntry(struct singleEntry * e
2049   printf("root=%s\n", s);   printf("root=%s\n", s);
2050      }      }
2051    
2052      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2053    
2054      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2055   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2056        printf("initrd=");
2057     else
2058        printf("initrd=%s", prefix);
2059    
2060   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2061      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2062   printf("\n");   printf("\n");
2063      }      }
2064    
2065        line = getLineByType(LT_TITLE, entry->lines);
2066        if (line) {
2067     printf("title=%s\n", line->elements[1].item);
2068        } else {
2069     char * title;
2070     line = getLineByType(LT_MENUENTRY, entry->lines);
2071     title = grub2ExtractTitle(line);
2072     if (title)
2073        printf("title=%s\n", title);
2074        }
2075    }
2076    
2077    int isSuseSystem(void) {
2078        const char * path;
2079        const static char default_path[] = "/etc/SuSE-release";
2080    
2081        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2082     path = default_path;
2083    
2084        if (!access(path, R_OK))
2085     return 1;
2086        return 0;
2087    }
2088    
2089    int isSuseGrubConf(const char * path) {
2090        FILE * grubConf;
2091        char * line = NULL;
2092        size_t len = 0, res = 0;
2093    
2094        grubConf = fopen(path, "r");
2095        if (!grubConf) {
2096            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2097     return 0;
2098        }
2099    
2100        while ((res = getline(&line, &len, grubConf)) != -1) {
2101     if (!strncmp(line, "setup", 5)) {
2102        fclose(grubConf);
2103        free(line);
2104        return 1;
2105     }
2106        }
2107    
2108        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2109          path);
2110    
2111        fclose(grubConf);
2112        free(line);
2113        return 0;
2114    }
2115    
2116    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2117        FILE * grubConf;
2118        char * line = NULL;
2119        size_t res = 0, len = 0;
2120    
2121        if (!path) return 1;
2122        if (!lbaPtr) return 1;
2123    
2124        grubConf = fopen(path, "r");
2125        if (!grubConf) return 1;
2126    
2127        while ((res = getline(&line, &len, grubConf)) != -1) {
2128     if (line[res - 1] == '\n')
2129        line[res - 1] = '\0';
2130     else if (len > res)
2131        line[res] = '\0';
2132     else {
2133        line = realloc(line, res + 1);
2134        line[res] = '\0';
2135     }
2136    
2137     if (!strncmp(line, "setup", 5)) {
2138        if (strstr(line, "--force-lba")) {
2139            *lbaPtr = 1;
2140        } else {
2141            *lbaPtr = 0;
2142        }
2143        dbgPrintf("lba: %i\n", *lbaPtr);
2144        break;
2145     }
2146        }
2147    
2148        free(line);
2149        fclose(grubConf);
2150        return 0;
2151    }
2152    
2153    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2154        FILE * grubConf;
2155        char * line = NULL;
2156        size_t res = 0, len = 0;
2157        char * lastParamPtr = NULL;
2158        char * secLastParamPtr = NULL;
2159        char installDeviceNumber = '\0';
2160        char * bounds = NULL;
2161    
2162        if (!path) return 1;
2163        if (!devicePtr) return 1;
2164    
2165        grubConf = fopen(path, "r");
2166        if (!grubConf) return 1;
2167    
2168        while ((res = getline(&line, &len, grubConf)) != -1) {
2169     if (strncmp(line, "setup", 5))
2170        continue;
2171    
2172     if (line[res - 1] == '\n')
2173        line[res - 1] = '\0';
2174     else if (len > res)
2175        line[res] = '\0';
2176     else {
2177        line = realloc(line, res + 1);
2178        line[res] = '\0';
2179     }
2180    
2181     lastParamPtr = bounds = line + res;
2182    
2183     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2184     while (!isspace(*lastParamPtr))
2185        lastParamPtr--;
2186     lastParamPtr++;
2187    
2188     secLastParamPtr = lastParamPtr - 2;
2189     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2190    
2191     if (lastParamPtr + 3 > bounds) {
2192        dbgPrintf("lastParamPtr going over boundary");
2193        fclose(grubConf);
2194        free(line);
2195        return 1;
2196     }
2197     if (!strncmp(lastParamPtr, "(hd", 3))
2198        lastParamPtr += 3;
2199     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2200    
2201     /*
2202     * Second last parameter will decide wether last parameter is
2203     * an IMAGE_DEVICE or INSTALL_DEVICE
2204     */
2205     while (!isspace(*secLastParamPtr))
2206        secLastParamPtr--;
2207     secLastParamPtr++;
2208    
2209     if (secLastParamPtr + 3 > bounds) {
2210        dbgPrintf("secLastParamPtr going over boundary");
2211        fclose(grubConf);
2212        free(line);
2213        return 1;
2214     }
2215     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2216     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2217        secLastParamPtr += 3;
2218        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2219        installDeviceNumber = *secLastParamPtr;
2220     } else {
2221        installDeviceNumber = *lastParamPtr;
2222     }
2223    
2224     *devicePtr = malloc(6);
2225     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2226     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2227     fclose(grubConf);
2228     free(line);
2229     return 0;
2230        }
2231    
2232        free(line);
2233        fclose(grubConf);
2234        return 1;
2235    }
2236    
2237    int grubGetBootFromDeviceMap(const char * device,
2238         char ** bootPtr) {
2239        FILE * deviceMap;
2240        char * line = NULL;
2241        size_t res = 0, len = 0;
2242        char * devicePtr;
2243        char * bounds = NULL;
2244        const char * path;
2245        const static char default_path[] = "/boot/grub/device.map";
2246    
2247        if (!device) return 1;
2248        if (!bootPtr) return 1;
2249    
2250        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2251     path = default_path;
2252    
2253        dbgPrintf("opening grub device.map file from: %s\n", path);
2254        deviceMap = fopen(path, "r");
2255        if (!deviceMap)
2256     return 1;
2257    
2258        while ((res = getline(&line, &len, deviceMap)) != -1) {
2259            if (!strncmp(line, "#", 1))
2260        continue;
2261    
2262     if (line[res - 1] == '\n')
2263        line[res - 1] = '\0';
2264     else if (len > res)
2265        line[res] = '\0';
2266     else {
2267        line = realloc(line, res + 1);
2268        line[res] = '\0';
2269     }
2270    
2271     devicePtr = line;
2272     bounds = line + res;
2273    
2274     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2275        devicePtr++;
2276     dbgPrintf("device: %s\n", devicePtr);
2277    
2278     if (!strncmp(devicePtr, device, strlen(device))) {
2279        devicePtr += strlen(device);
2280        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2281            devicePtr++;
2282    
2283        *bootPtr = strdup(devicePtr);
2284        break;
2285     }
2286        }
2287    
2288        free(line);
2289        fclose(deviceMap);
2290        return 0;
2291    }
2292    
2293    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2294        char * grubDevice;
2295    
2296        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2297     dbgPrintf("error looking for grub installation device\n");
2298        else
2299     dbgPrintf("grubby installation device: %s\n", grubDevice);
2300    
2301        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2302     dbgPrintf("error looking for grub boot device\n");
2303        else
2304     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2305    
2306        free(grubDevice);
2307        return 0;
2308    }
2309    
2310    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2311        /*
2312         * This SuSE grub configuration file at this location is not your average
2313         * grub configuration file, but instead the grub commands used to setup
2314         * grub on that system.
2315         */
2316        const char * path;
2317        const static char default_path[] = "/etc/grub.conf";
2318    
2319        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2320     path = default_path;
2321    
2322        if (!isSuseGrubConf(path)) return 1;
2323    
2324        if (lbaPtr) {
2325            *lbaPtr = 0;
2326            if (suseGrubConfGetLba(path, lbaPtr))
2327                return 1;
2328        }
2329    
2330        if (bootPtr) {
2331            *bootPtr = NULL;
2332            suseGrubConfGetBoot(path, bootPtr);
2333        }
2334    
2335        return 0;
2336  }  }
2337    
2338  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2342  int parseSysconfigGrub(int * lbaPtr, cha
2342      char * start;      char * start;
2343      char * param;      char * param;
2344    
2345      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2346      if (!in) return 1;      if (!in) return 1;
2347    
2348      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2383  int parseSysconfigGrub(int * lbaPtr, cha
2383  }  }
2384    
2385  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2386      char * boot;      char * boot = NULL;
2387      int lba;      int lba;
2388    
2389      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2390   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2391   if (boot) printf("boot=%s\n", boot);      free(boot);
2392        return;
2393     }
2394        } else {
2395            if (parseSysconfigGrub(&lba, &boot)) {
2396        free(boot);
2397        return;
2398     }
2399        }
2400    
2401        if (lba) printf("lba\n");
2402        if (boot) {
2403     printf("boot=%s\n", boot);
2404     free(boot);
2405      }      }
2406  }  }
2407    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2417  int displayInfo(struct grubConfig * conf
2417   return 1;   return 1;
2418      }      }
2419    
2420      /* 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
2421         be a better way */         be a better way */
2422      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2423   dumpSysconfigGrub();   dumpSysconfigGrub();
2424      } else {      } else {
2425   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2426   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2427      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2428   }   }
2429    
2430   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2431   if (line) printf("lba\n");   if (line) printf("lba\n");
2432      }      }
2433    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2442  int displayInfo(struct grubConfig * conf
2442      return 0;      return 0;
2443  }  }
2444    
2445    struct singleLine * addLineTmpl(struct singleEntry * entry,
2446     struct singleLine * tmplLine,
2447     struct singleLine * prevLine,
2448     const char * val,
2449     struct configFileInfo * cfi)
2450    {
2451        struct singleLine * newLine = lineDup(tmplLine);
2452    
2453        if (isEfi && cfi == &grub2ConfigType) {
2454     enum lineType_e old = newLine->type;
2455     newLine->type = preferredLineType(newLine->type, cfi);
2456     if (old != newLine->type)
2457        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2458        }
2459    
2460        if (val) {
2461     /* override the inherited value with our own.
2462     * This is a little weak because it only applies to elements[1]
2463     */
2464     if (newLine->numElements > 1)
2465        removeElement(newLine, 1);
2466     insertElement(newLine, val, 1, cfi);
2467    
2468     /* but try to keep the rootspec from the template... sigh */
2469     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2470        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2471        if (rootspec != NULL) {
2472     free(newLine->elements[1].item);
2473     newLine->elements[1].item =
2474        sdupprintf("%s%s", rootspec, val);
2475        }
2476     }
2477        }
2478    
2479        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2480          newLine->elements[0].item : "");
2481    
2482        if (!entry->lines) {
2483     /* first one on the list */
2484     entry->lines = newLine;
2485        } else if (prevLine) {
2486     /* add after prevLine */
2487     newLine->next = prevLine->next;
2488     prevLine->next = newLine;
2489        }
2490    
2491        return newLine;
2492    }
2493    
2494  /* val may be NULL */  /* val may be NULL */
2495  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2496       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2497       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2498       char * val) {       const char * val) {
2499      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2500      int i;      struct keywordTypes * kw;
2501        struct singleLine tmpl;
2502    
2503      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2504   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2505      if (type != LT_TITLE || !cfi->titleBracketed)       */
2506          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2507     /* we're doing a bracketed title (zipl) */
2508     tmpl.type = type;
2509     tmpl.numElements = 1;
2510     tmpl.elements = alloca(sizeof(*tmpl.elements));
2511     tmpl.elements[0].item = alloca(strlen(val)+3);
2512     sprintf(tmpl.elements[0].item, "[%s]", val);
2513     tmpl.elements[0].indent = "";
2514     val = NULL;
2515        } else if (type == LT_MENUENTRY) {
2516     char *lineend = "--class gnu-linux --class gnu --class os {";
2517     if (!val) {
2518        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2519        abort();
2520     }
2521     kw = getKeywordByType(type, cfi);
2522     if (!kw) {
2523        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2524        abort();
2525     }
2526     tmpl.indent = "";
2527     tmpl.type = type;
2528     tmpl.numElements = 3;
2529     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2530     tmpl.elements[0].item = kw->key;
2531     tmpl.elements[0].indent = alloca(2);
2532     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2533     tmpl.elements[1].item = (char *)val;
2534     tmpl.elements[1].indent = alloca(2);
2535     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2536     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2537     strcpy(tmpl.elements[2].item, lineend);
2538     tmpl.elements[2].indent = "";
2539        } else {
2540     kw = getKeywordByType(type, cfi);
2541     if (!kw) {
2542        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2543        abort();
2544     }
2545     tmpl.type = type;
2546     tmpl.numElements = val ? 2 : 1;
2547     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2548     tmpl.elements[0].item = kw->key;
2549     tmpl.elements[0].indent = alloca(2);
2550     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2551     if (val) {
2552        tmpl.elements[1].item = (char *)val;
2553        tmpl.elements[1].indent = "";
2554     }
2555        }
2556    
2557      /* 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
2558         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2559         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
2560         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2561         differently from the rest) */         differently from the rest) */
2562      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2563   line = entry->lines;   if (line->numElements) prev = line;
2564   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2565   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;  
2566      }      }
2567    
2568      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2569          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2570          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2571          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2572          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2573          line->elements[0].indent = malloc(2);   else
2574          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2575          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2576             if (menuEntry)
2577          if (val) {      tmpl.indent = "\t";
2578              line->elements[1].item = val;   else if (prev == entry->lines)
2579              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2580          }   else
2581      } 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("");  
2582      }      }
2583    
2584      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2585  }  }
2586    
2587  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2606  void removeLine(struct singleEntry * ent
2606      free(line);      free(line);
2607  }  }
2608    
2609    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2610    {
2611        struct singleLine newLine = {
2612     .indent = tmplLine->indent,
2613     .type = tmplLine->type,
2614     .next = tmplLine->next,
2615        };
2616        int firstQuotedItem = -1;
2617        int quoteLen = 0;
2618        int j;
2619        int element = 0;
2620        char *c;
2621    
2622        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2623        strcpy(c, tmplLine->elements[0].item);
2624        insertElement(&newLine, c, element++, cfi);
2625        free(c);
2626        c = NULL;
2627    
2628        for (j = 1; j < tmplLine->numElements; j++) {
2629     if (firstQuotedItem == -1) {
2630        quoteLen += strlen(tmplLine->elements[j].item);
2631        
2632        if (isquote(tmplLine->elements[j].item[0])) {
2633     firstQuotedItem = j;
2634            quoteLen += strlen(tmplLine->elements[j].indent);
2635        } else {
2636     c = malloc(quoteLen + 1);
2637     strcpy(c, tmplLine->elements[j].item);
2638     insertElement(&newLine, c, element++, cfi);
2639     free(c);
2640     quoteLen = 0;
2641        }
2642     } else {
2643        int itemlen = strlen(tmplLine->elements[j].item);
2644        quoteLen += itemlen;
2645        quoteLen += strlen(tmplLine->elements[j].indent);
2646        
2647        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2648     c = malloc(quoteLen + 1);
2649     c[0] = '\0';
2650     for (int i = firstQuotedItem; i < j+1; i++) {
2651        strcat(c, tmplLine->elements[i].item);
2652        strcat(c, tmplLine->elements[i].indent);
2653     }
2654     insertElement(&newLine, c, element++, cfi);
2655     free(c);
2656    
2657     firstQuotedItem = -1;
2658     quoteLen = 0;
2659        }
2660     }
2661        }
2662        while (tmplLine->numElements)
2663     removeElement(tmplLine, 0);
2664        if (tmplLine->elements)
2665     free(tmplLine->elements);
2666    
2667        tmplLine->numElements = newLine.numElements;
2668        tmplLine->elements = newLine.elements;
2669    }
2670    
2671    static void insertElement(struct singleLine * line,
2672      const char * item, int insertHere,
2673      struct configFileInfo * cfi)
2674    {
2675        struct keywordTypes * kw;
2676        char indent[2] = "";
2677    
2678        /* sanity check */
2679        if (insertHere > line->numElements) {
2680     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2681      insertHere, line->numElements);
2682     insertHere = line->numElements;
2683        }
2684    
2685        line->elements = realloc(line->elements, (line->numElements + 1) *
2686         sizeof(*line->elements));
2687        memmove(&line->elements[insertHere+1],
2688        &line->elements[insertHere],
2689        (line->numElements - insertHere) *
2690        sizeof(*line->elements));
2691        line->elements[insertHere].item = strdup(item);
2692    
2693        kw = getKeywordByType(line->type, cfi);
2694    
2695        if (line->numElements == 0) {
2696     indent[0] = '\0';
2697        } else if (insertHere == 0) {
2698     indent[0] = kw->nextChar;
2699        } else if (kw->separatorChar != '\0') {
2700     indent[0] = kw->separatorChar;
2701        } else {
2702     indent[0] = ' ';
2703        }
2704    
2705        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2706     /* move the end-of-line forward */
2707     line->elements[insertHere].indent =
2708        line->elements[insertHere-1].indent;
2709     line->elements[insertHere-1].indent = strdup(indent);
2710        } else {
2711     line->elements[insertHere].indent = strdup(indent);
2712        }
2713    
2714        line->numElements++;
2715    
2716        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2717          line->elements[0].item,
2718          line->elements[insertHere].item,
2719          line->elements[insertHere].indent,
2720          insertHere);
2721    }
2722    
2723    static void removeElement(struct singleLine * line, int removeHere) {
2724        int i;
2725    
2726        /* sanity check */
2727        if (removeHere >= line->numElements) return;
2728    
2729        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2730          removeHere, line->elements[removeHere].item);
2731    
2732        free(line->elements[removeHere].item);
2733    
2734        if (removeHere > 1) {
2735     /* previous argument gets this argument's post-indentation */
2736     free(line->elements[removeHere-1].indent);
2737     line->elements[removeHere-1].indent =
2738        line->elements[removeHere].indent;
2739        } else {
2740     free(line->elements[removeHere].indent);
2741        }
2742    
2743        /* now collapse the array, but don't bother to realloc smaller */
2744        for (i = removeHere; i < line->numElements - 1; i++)
2745     line->elements[i] = line->elements[i + 1];
2746    
2747        line->numElements--;
2748    }
2749    
2750  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2751      char * first, * second;      char * first, * second;
2752      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2769  int updateActualImage(struct grubConfig
2769      struct singleEntry * entry;      struct singleEntry * entry;
2770      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2771      int index = 0;      int index = 0;
2772      int i, j, k;      int i, k;
2773      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2774      const char ** arg;      const char ** arg;
2775      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2776      int firstElement;      int firstElement;
2777      int *usedElements, *usedArgs;      int *usedElements;
2778        int doreplace;
2779    
2780      if (!image) return 0;      if (!image) return 0;
2781    
# Line 1609  int updateActualImage(struct grubConfig Line 2802  int updateActualImage(struct grubConfig
2802   }   }
2803      }      }
2804    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2805    
2806      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2807   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2808    
2809      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2810   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2811    
2812      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2813    
2814      k = 0;   if (multibootArgs && !entry->multiboot)
2815      for (arg = newArgs; *arg; arg++)      continue;
2816          k++;  
2817      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2818     * LT_KERNELARGS, use that.  Otherwise use
2819     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2820     */
2821     if (useKernelArgs) {
2822        line = getLineByType(LT_KERNELARGS, entry->lines);
2823        if (!line) {
2824     /* no LT_KERNELARGS, need to add it */
2825     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2826           cfg->secondaryIndent, NULL);
2827        }
2828        firstElement = 1;
2829    
2830      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2831   index++;      line = getLineByType(LT_HYPER, entry->lines);
2832        if (!line) {
2833     /* a multiboot entry without LT_HYPER? */
2834     continue;
2835        }
2836        firstElement = 2;
2837    
2838   line = entry->lines;   } else {
2839   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
2840   if (!line) continue;      if (!line) {
2841   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2842     continue;
2843          if (entry->multiboot && !multibootArgs) {      }
2844              /* 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;  
2845   }   }
2846    
2847   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2848      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2849      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2850     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2851        /* this is a multiboot entry, make sure there's
2852         * -- on the args line
2853         */
2854        for (i = firstElement; i < line->numElements; i++) {
2855     if (!strcmp(line->elements[i].item, "--"))
2856        break;
2857        }
2858        if (i == line->numElements) {
2859     /* assume all existing args are kernel args,
2860     * prepend -- to make it official
2861     */
2862     insertElement(line, "--", firstElement, cfg->cfi);
2863     i = firstElement;
2864        }
2865        if (!multibootArgs) {
2866     /* kernel args start after the -- */
2867     firstElement = i + 1;
2868        }
2869     } else if (cfg->cfi->mbConcatArgs) {
2870        /* this is a non-multiboot entry, remove hyper args */
2871        for (i = firstElement; i < line->numElements; i++) {
2872     if (!strcmp(line->elements[i].item, "--"))
2873        break;
2874        }
2875        if (i < line->numElements) {
2876     /* remove args up to -- */
2877     while (strcmp(line->elements[firstElement].item, "--"))
2878        removeElement(line, firstElement);
2879     /* remove -- */
2880     removeElement(line, firstElement);
2881        }
2882   }   }
2883    
2884          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2885    
2886          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2887   for (arg = newArgs; *arg; arg++) {  
2888              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2889      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2890     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2891        !strcmp(line->elements[i].item, "--"))
2892     {
2893        /* reached the end of hyper args, insert here */
2894        doreplace = 0;
2895        break;  
2896     }
2897                  if (usedElements[i])                  if (usedElements[i])
2898                      continue;                      continue;
2899   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2900                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2901      break;      break;
2902                  }                  }
2903              }              }
     chptr = strchr(*arg, '=');  
2904    
2905      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2906   /* replace */   /* direct replacement */
2907   free(line->elements[i].item);   free(line->elements[i].item);
2908   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("");  
  }  
2909    
2910   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2911   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2912      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2913   /* append */   if (rootLine) {
2914   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2915   (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(" ");  
2916   } else {   } else {
2917      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2918         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2919   }   }
2920        }
2921    
2922   line->numElements++;      else {
2923     /* insert/append */
2924     insertElement(line, *arg, i, cfg->cfi);
2925     usedElements = realloc(usedElements, line->numElements *
2926           sizeof(*usedElements));
2927     memmove(&usedElements[i + 1], &usedElements[i],
2928     line->numElements - i - 1);
2929     usedElements[i] = 1;
2930    
2931   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2932     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2933     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2934   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2935      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2936      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2937   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2938   }   }
2939      }      }
             k++;  
2940   }   }
2941    
2942          free(usedElements);          free(usedElements);
2943    
  /* 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? */  
2944   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2945      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2946   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2947        !strcmp(line->elements[i].item, "--"))
2948        /* reached the end of hyper args, stop here */
2949        break;
2950     if (!argMatch(line->elements[i].item, *arg)) {
2951        removeElement(line, i);
2952      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;  
2953   }   }
2954        }
2955   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2956        if (useRoot && !strncmp(*arg, "root=", 5)) {
2957   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2958      line->elements[j - 1] = line->elements[j];   if (rootLine)
2959        removeLine(entry, rootLine);
  line->numElements--;  
2960      }      }
2961   }   }
2962    
# Line 1760  int updateActualImage(struct grubConfig Line 2967  int updateActualImage(struct grubConfig
2967   }   }
2968      }      }
2969    
     free(usedArgs);  
2970      free(newArgs);      free(newArgs);
2971      free(oldArgs);      free(oldArgs);
2972    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2992  int updateImage(struct grubConfig * cfg,
2992      return rc;      return rc;
2993  }  }
2994    
2995    int updateInitrd(struct grubConfig * cfg, const char * image,
2996                     const char * prefix, const char * initrd) {
2997        struct singleEntry * entry;
2998        struct singleLine * line, * kernelLine, *endLine = NULL;
2999        int index = 0;
3000    
3001        if (!image) return 0;
3002    
3003        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3004            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3005            if (!kernelLine) continue;
3006    
3007            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3008            if (line)
3009                removeLine(entry, line);
3010            if (prefix) {
3011                int prefixLen = strlen(prefix);
3012                if (!strncmp(initrd, prefix, prefixLen))
3013                    initrd += prefixLen;
3014            }
3015     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3016     if (endLine)
3017        removeLine(entry, endLine);
3018            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3019     kernelLine->indent, initrd);
3020            if (!line)
3021        return 1;
3022     if (endLine) {
3023        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3024                if (!line)
3025     return 1;
3026     }
3027    
3028            break;
3029        }
3030    
3031        return 0;
3032    }
3033    
3034  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3035      int fd;      int fd;
3036      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3054  int checkDeviceBootloader(const char * d
3054      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3055   return 0;   return 0;
3056    
3057      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3058   offset = boot[2] + 2;   offset = boot[2] + 2;
3059      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3060   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3061      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3062   offset = boot[1] + 2;        offset = boot[1] + 2;
3063            /*
3064     * it looks like grub, when copying stage1 into the mbr, patches stage1
3065     * right after the JMP location, replacing other instructions such as
3066     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3067     * different bytes.
3068     */
3069          if ((bootSect[offset + 1] == NOOP_OPCODE)
3070      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3071     offset = offset + 3;
3072          }
3073      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3074   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3075      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3211  int checkForLilo(struct grubConfig * con
3211      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3212  }  }
3213    
3214    int checkForGrub2(struct grubConfig * config) {
3215        if (!access("/etc/grub.d/", R_OK))
3216     return 2;
3217    
3218        return 1;
3219    }
3220    
3221  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3222      int fd;      int fd;
3223      unsigned char bootSect[512];      unsigned char bootSect[512];
3224      char * boot;      char * boot;
3225        int onSuse = isSuseSystem();
3226    
3227      if (parseSysconfigGrub(NULL, &boot))  
3228   return 0;      if (onSuse) {
3229     if (parseSuseGrubConf(NULL, &boot))
3230        return 0;
3231        } else {
3232     if (parseSysconfigGrub(NULL, &boot))
3233        return 0;
3234        }
3235    
3236      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3237      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3245  int checkForGrub(struct grubConfig * con
3245      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3246   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3247   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3248     close(fd);
3249   return 1;   return 1;
3250      }      }
3251      close(fd);      close(fd);
3252    
3253        /* The more elaborate checks do not work on SuSE. The checks done
3254         * seem to be reasonble (at least for now), so just return success
3255         */
3256        if (onSuse)
3257     return 2;
3258    
3259      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3260  }  }
3261    
3262    int checkForExtLinux(struct grubConfig * config) {
3263        int fd;
3264        unsigned char bootSect[512];
3265        char * boot;
3266        char executable[] = "/boot/extlinux/extlinux";
3267    
3268        printf("entered: checkForExtLinux()\n");
3269    
3270        if (parseSysconfigGrub(NULL, &boot))
3271     return 0;
3272    
3273        /* assume grub is not installed -- not an error condition */
3274        if (!boot)
3275     return 0;
3276    
3277        fd = open(executable, O_RDONLY);
3278        if (fd < 0)
3279     /* this doesn't exist if grub hasn't been installed */
3280     return 0;
3281    
3282        if (read(fd, bootSect, 512) != 512) {
3283     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3284     executable, strerror(errno));
3285     return 1;
3286        }
3287        close(fd);
3288    
3289        return checkDeviceBootloader(boot, bootSect);
3290    }
3291    
3292    int checkForYaboot(struct grubConfig * config) {
3293        /*
3294         * This is a simplistic check that we consider good enough for own puporses
3295         *
3296         * If we were to properly check if yaboot is *installed* we'd need to:
3297         * 1) get the system boot device (LT_BOOT)
3298         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3299         *    the content on the boot device
3300         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3301         * 4) check again if binary and boot device contents match
3302         */
3303        if (!access("/etc/yaboot.conf", R_OK))
3304     return 2;
3305    
3306        return 1;
3307    }
3308    
3309    int checkForElilo(struct grubConfig * config) {
3310        if (!access("/etc/elilo.conf", R_OK))
3311     return 2;
3312    
3313        return 1;
3314    }
3315    
3316  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3317      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3318    
# Line 1994  static char * getRootSpecifier(char * st Line 3324  static char * getRootSpecifier(char * st
3324      return rootspec;      return rootspec;
3325  }  }
3326    
3327    static char * getInitrdVal(struct grubConfig * config,
3328       const char * prefix, struct singleLine *tmplLine,
3329       const char * newKernelInitrd,
3330       const char ** extraInitrds, int extraInitrdCount)
3331    {
3332        char *initrdVal, *end;
3333        int i;
3334        size_t totalSize;
3335        size_t prefixLen;
3336        char separatorChar;
3337    
3338        prefixLen = strlen(prefix);
3339        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3340    
3341        for (i = 0; i < extraInitrdCount; i++) {
3342     totalSize += sizeof(separatorChar);
3343     totalSize += strlen(extraInitrds[i]) - prefixLen;
3344        }
3345    
3346        initrdVal = end = malloc(totalSize);
3347    
3348        end = stpcpy (end, newKernelInitrd + prefixLen);
3349    
3350        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3351        for (i = 0; i < extraInitrdCount; i++) {
3352     const char *extraInitrd;
3353     int j;
3354    
3355     extraInitrd = extraInitrds[i] + prefixLen;
3356     /* Don't add entries that are already there */
3357     if (tmplLine != NULL) {
3358        for (j = 2; j < tmplLine->numElements; j++)
3359     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3360        break;
3361    
3362        if (j != tmplLine->numElements)
3363     continue;
3364     }
3365    
3366     *end++ = separatorChar;
3367     end = stpcpy(end, extraInitrd);
3368        }
3369    
3370        return initrdVal;
3371    }
3372    
3373  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3374           const char * prefix,           const char * prefix,
3375   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3376   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3377                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3378                     const char * newMBKernel, const char * newMBKernelArgs) {
3379      struct singleEntry * new;      struct singleEntry * new;
3380      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3381      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3382      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3383    
3384      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3385    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3409  int addNewKernel(struct grubConfig * con
3409      config->entries = new;      config->entries = new;
3410    
3411      /* copy/update from the template */      /* copy/update from the template */
3412      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3413        if (newKernelInitrd)
3414     needs |= NEED_INITRD;
3415      if (newMBKernel) {      if (newMBKernel) {
3416          needs |= KERNEL_MB;          needs |= NEED_MB;
3417          new->multiboot = 1;          new->multiboot = 1;
3418      }      }
3419    
3420      if (template) {      if (template) {
3421   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3422      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3423      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3424   indent = tmplLine->indent;   {
3425        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3426    
3427      /* skip comments */      /* skip comments */
3428      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3429      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3430      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3431    
3432      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3433      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3434        /* it's not a multiboot template and this is the kernel
3435              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3436                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3437                  struct singleLine *l;       */
3438                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3439     /* insert the hypervisor first */
3440                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3441                                    config->secondaryIndent,    tmplLine->indent,
3442                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3443                     /* set up for adding the kernel line */
3444                  tmplLine = lastLine;   free(tmplLine->indent);
3445                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3446                      new->lines = l;   needs &= ~NEED_MB;
3447                  } else {      }
3448                      newLine->next = l;      if (needs & NEED_KERNEL) {
3449                      newLine = l;   /* use addLineTmpl to preserve line elements,
3450                  }   * otherwise we could just call addLine.  Unfortunately
3451                  continue;   * this means making some changes to the template
3452              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3453                         template->multiboot && !new->multiboot) {   * change below.
3454                  continue; /* don't need multiboot kernel here */   */
3455              }   struct keywordTypes * mbm_kw =
3456        getKeywordByType(LT_MBMODULE, config->cfi);
3457      if (!new->lines) {   if (mbm_kw) {
3458   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3459   new->lines = newLine;      free(tmplLine->elements[0].item);
3460      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3461   newLine->next = malloc(sizeof(*newLine));   }
3462   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3463      }        newKernelPath + strlen(prefix), config->cfi);
3464     needs &= ~NEED_KERNEL;
3465        }
3466        if (needs & NEED_MB) { /* !mbHyperFirst */
3467     newLine = addLine(new, config->cfi, LT_HYPER,
3468      config->secondaryIndent,
3469      newMBKernel + strlen(prefix));
3470     needs &= ~NEED_MB;
3471        }
3472     } else if (needs & NEED_KERNEL) {
3473        newLine = addLineTmpl(new, tmplLine, newLine,
3474      newKernelPath + strlen(prefix), config->cfi);
3475        needs &= ~NEED_KERNEL;
3476     }
3477    
3478        } else if (tmplLine->type == LT_HYPER &&
3479           tmplLine->numElements >= 2) {
3480     if (needs & NEED_MB) {
3481        newLine = addLineTmpl(new, tmplLine, newLine,
3482      newMBKernel + strlen(prefix), config->cfi);
3483        needs &= ~NEED_MB;
3484     }
3485    
3486      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3487      newLine->next = NULL;         tmplLine->numElements >= 2) {
3488      newLine->type = tmplLine->type;   if (new->multiboot) {
3489      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3490      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3491      newLine->numElements);        newKernelPath +
3492      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3493   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3494   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3495   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3496      }   char *initrdVal;
3497     initrdVal = getInitrdVal(config, prefix, tmplLine,
3498              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3499      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3500                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3501                  if (!template->multiboot) {        initrdVal, config->cfi);
3502                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3503                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3504                  } else {      }
3505                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3506                      repl = newMBKernel;      /* template is multi but new is not,
3507                  }       * insert the kernel in the first module slot
3508                  if (new->multiboot && !template->multiboot) {       */
3509                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3510                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3511                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3512                  }   strdup(getKeywordByType(tmplLine->type,
3513   free(newLine->elements[1].item);   config->cfi)->key);
3514                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3515                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3516                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3517                                                             rootspec,      needs &= ~NEED_KERNEL;
3518                                                             repl +   } else if (needs & NEED_INITRD) {
3519                                                             strlen(prefix));      char *initrdVal;
3520                  } else {      /* template is multi but new is not,
3521                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3522                                                         strlen(prefix));       */
3523                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3524              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3525                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3526                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3527                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3528                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3529                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3530                      newLine->type = LT_KERNEL;      free(initrdVal);
3531                  }      needs &= ~NEED_INITRD;
3532   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));  
                 }  
     } else if (tmplLine->type == LT_INITRD &&  
     tmplLine->numElements >= 2) {  
  needs &= ~KERNEL_INITRD;  
  free(newLine->elements[1].item);  
                 if (new->multiboot && !template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("module");  
                     newLine->type = LT_MBMODULE;  
                 }  
                 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_MBMODULE &&  
                        tmplLine->numElements >= 2 && (needs & KERNEL_INITRD)) {  
  needs &= ~KERNEL_INITRD;  
                 if (!new->multiboot && template->multiboot) {  
                     free(newLine->elements[0].item);  
                     newLine->elements[0].item = strdup("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;  
3533    
3534   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3535      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3536      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3537        config->cfi->mbInitRdIsModule) {
3538        /* make sure we don't insert the module initrd
3539         * before the module kernel... if we don't do it here,
3540         * it will be inserted following the template.
3541         */
3542        if (!needs & NEED_KERNEL) {
3543     char *initrdVal;
3544    
3545     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3546     newLine = addLine(new, config->cfi, LT_MBMODULE,
3547      config->secondaryIndent,
3548      initrdVal);
3549     free(initrdVal);
3550     needs &= ~NEED_INITRD;
3551        }
3552     } else if (needs & NEED_INITRD) {
3553        char *initrdVal;
3554        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3555        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3556        free(initrdVal);
3557        needs &= ~NEED_INITRD;
3558   }   }
3559    
3560   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3561   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3562   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3563     char *nkt = malloc(strlen(newKernelTitle)+3);
3564     strcpy(nkt, "'");
3565     strcat(nkt, newKernelTitle);
3566     strcat(nkt, "'");
3567     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3568     free(nkt);
3569     needs &= ~NEED_TITLE;
3570      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3571                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3572                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3573                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3574                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3575                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3576                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3577                                             newLine->numElements);     config->cfi->titleBracketed) {
3578        /* addLineTmpl doesn't handle titleBracketed */
3579                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3580                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3581                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3582                  newLine->numElements = 1;   }
3583              }      } else if (tmplLine->type == LT_ECHO) {
3584        requote(tmplLine, config->cfi);
3585        static const char *prefix = "'Loading ";
3586        if (tmplLine->numElements > 1 &&
3587        strstr(tmplLine->elements[1].item, prefix) &&
3588        masterLine->next &&
3589        iskernel(masterLine->next->type)) {
3590     char *newTitle = malloc(strlen(prefix) +
3591     strlen(newKernelTitle) + 2);
3592    
3593     strcpy(newTitle, prefix);
3594     strcat(newTitle, newKernelTitle);
3595     strcat(newTitle, "'");
3596     newLine = addLine(new, config->cfi, LT_ECHO,
3597     tmplLine->indent, newTitle);
3598     free(newTitle);
3599        } else {
3600     /* pass through other lines from the template */
3601     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3602     config->cfi);
3603        }
3604        } else {
3605     /* pass through other lines from the template */
3606     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3607        }
3608   }   }
3609    
3610      } else {      } else {
3611   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3612      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3613     */
3614     switch (config->cfi->entryStart) {
3615        case LT_KERNEL:
3616        case LT_KERNEL_EFI:
3617     if (new->multiboot && config->cfi->mbHyperFirst) {
3618        /* fall through to LT_HYPER */
3619     } else {
3620        newLine = addLine(new, config->cfi,
3621              preferredLineType(LT_KERNEL, config->cfi),
3622          config->primaryIndent,
3623          newKernelPath + strlen(prefix));
3624        needs &= ~NEED_KERNEL;
3625        break;
3626     }
3627    
3628        case LT_HYPER:
3629     newLine = addLine(new, config->cfi, LT_HYPER,
3630      config->primaryIndent,
3631      newMBKernel + strlen(prefix));
3632     needs &= ~NEED_MB;
3633   break;   break;
         }  
3634    
3635   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3636      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3637       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3638       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3639      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3640       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3641      default:        config->primaryIndent, nkt);
3642                  /* zipl strikes again */   free(nkt);
3643                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3644                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3645                      chptr = newKernelTitle;   break;
3646                      type = LT_TITLE;      }
3647                      break;      case LT_TITLE:
3648                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3649                      abort();   char * templabel;
3650                  }   int x = 0, y = 0;
3651   }  
3652     templabel = strdup(newKernelTitle);
3653     while( templabel[x]){
3654     if( templabel[x] == ' ' ){
3655     y = x;
3656     while( templabel[y] ){
3657     templabel[y] = templabel[y+1];
3658     y++;
3659     }
3660     }
3661     x++;
3662     }
3663     newLine = addLine(new, config->cfi, LT_TITLE,
3664      config->primaryIndent, templabel);
3665     free(templabel);
3666     }else{
3667     newLine = addLine(new, config->cfi, LT_TITLE,
3668      config->primaryIndent, newKernelTitle);
3669     }
3670     needs &= ~NEED_TITLE;
3671     break;
3672    
3673   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3674   new->lines = newLine;   abort();
3675     }
3676      }      }
3677    
3678      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3679          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3680              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3681                                config->secondaryIndent,       */
3682                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3683          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3684              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3685                                config->secondaryIndent,    newKernelTitle);
3686                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3687          /* don't need to check for title as it's guaranteed to have been      }
3688           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3689           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3690          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3691              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3692                                config->secondaryIndent,   needs &= ~NEED_MB;
3693                                newKernelInitrd + strlen(prefix));      }
3694      } else {      if (needs & NEED_KERNEL) {
3695          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3696              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3697                                config->secondaryIndent,        config->cfi))
3698                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3699          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3700              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3701                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3702                                newKernelTitle);   needs &= ~NEED_KERNEL;
3703          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3704              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3705                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3706                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3707      newMBKernel + strlen(prefix));
3708     needs &= ~NEED_MB;
3709        }
3710        if (needs & NEED_INITRD) {
3711     char *initrdVal;
3712     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3713     newLine = addLine(new, config->cfi,
3714      (new->multiboot && getKeywordByType(LT_MBMODULE,
3715          config->cfi))
3716       ? LT_MBMODULE
3717       : preferredLineType(LT_INITRD, config->cfi),
3718      config->secondaryIndent,
3719      initrdVal);
3720     free(initrdVal);
3721     needs &= ~NEED_INITRD;
3722        }
3723        if (needs & NEED_END) {
3724     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3725     config->secondaryIndent, NULL);
3726     needs &= ~NEED_END;
3727        }
3728    
3729        if (needs) {
3730     printf(_("grubby: needs=%d, aborting\n"), needs);
3731     abort();
3732      }      }
3733    
3734      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3737  int addNewKernel(struct grubConfig * con
3737      return 0;      return 0;
3738  }  }
3739    
3740    static void traceback(int signum)
3741    {
3742        void *array[40];
3743        size_t size;
3744    
3745        signal(SIGSEGV, SIG_DFL);
3746        memset(array, '\0', sizeof (array));
3747        size = backtrace(array, 40);
3748    
3749        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3750                (unsigned long)size);
3751        backtrace_symbols_fd(array, size, STDERR_FILENO);
3752        exit(1);
3753    }
3754    
3755  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3756      poptContext optCon;      poptContext optCon;
3757      char * grubConfig = NULL;      const char * grubConfig = NULL;
3758      char * outputFile = NULL;      char * outputFile = NULL;
3759      int arg = 0;      int arg = 0;
3760      int flags = 0;      int flags = 0;
3761      int badImageOkay = 0;      int badImageOkay = 0;
3762        int configureGrub2 = 0;
3763      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3764      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3765        int configureExtLinux = 0;
3766      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3767        int extraInitrdCount = 0;
3768      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3769      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3770      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3780  int main(int argc, const char ** argv) {
3780      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3781      char * removeArgs = NULL;      char * removeArgs = NULL;
3782      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3783        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3784      const char * chptr = NULL;      const char * chptr = NULL;
3785      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3786      struct grubConfig * config;      struct grubConfig * config;
3787      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3788      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3789      int displayDefault = 0;      int displayDefault = 0;
3790        int displayDefaultIndex = 0;
3791        int displayDefaultTitle = 0;
3792        int defaultIndex = -1;
3793      struct poptOption options[] = {      struct poptOption options[] = {
3794   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3795      _("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 3807  int main(int argc, const char ** argv) {
3807   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3808      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3809      _("bootfs") },      _("bootfs") },
3810  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3811   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3812      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3813  #endif  #endif
3814   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3815      _("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 3820  int main(int argc, const char ** argv) {
3820        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3821        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3822        "template"), NULL },        "template"), NULL },
3823     { "debug", 0, 0, &debug, 0,
3824        _("print debugging information for failures") },
3825   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3826      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3827     { "default-index", 0, 0, &displayDefaultIndex, 0,
3828        _("display the index of the default kernel") },
3829     { "default-title", 0, 0, &displayDefaultTitle, 0,
3830        _("display the title of the default kernel") },
3831   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3832      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3833     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
3834        _("force grub2 stanzas to use efi") },
3835     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3836        _("configure extlinux bootloader (from syslinux)") },
3837   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3838      _("configure grub bootloader") },      _("configure grub bootloader") },
3839     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3840        _("configure grub2 bootloader") },
3841   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3842      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3843      _("kernel-path") },      _("kernel-path") },
3844   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3845      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3846     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3847        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3848   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3849      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3850   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3864  int main(int argc, const char ** argv) {
3864   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3865      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3866        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3867     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3868        _("make the given entry index the default entry"),
3869        _("entry-index") },
3870   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3871      _("configure silo bootloader") },      _("configure silo bootloader") },
3872   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3884  int main(int argc, const char ** argv) {
3884   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3885      };      };
3886    
3887        useextlinuxmenu=0;
3888    
3889        signal(SIGSEGV, traceback);
3890    
3891      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3892      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3893    
# Line 2391  int main(int argc, const char ** argv) { Line 3897  int main(int argc, const char ** argv) {
3897      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3898      exit(0);      exit(0);
3899      break;      break;
3900      case 'i':
3901        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3902         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3903        } else {
3904     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3905     return 1;
3906        }
3907        break;
3908   }   }
3909      }      }
3910    
# Line 2406  int main(int argc, const char ** argv) { Line 3920  int main(int argc, const char ** argv) {
3920   return 1;   return 1;
3921      }      }
3922    
3923      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3924   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3925     configureExtLinux ) > 1) {
3926   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3927   return 1;   return 1;
3928      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3929   fprintf(stderr,   fprintf(stderr,
3930      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3931   return 1;   return 1;
3932        } else if (configureGrub2) {
3933     cfi = &grub2ConfigType;
3934      } else if (configureLilo) {      } else if (configureLilo) {
3935   cfi = &liloConfigType;   cfi = &liloConfigType;
3936      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3943  int main(int argc, const char ** argv) {
3943          cfi = &siloConfigType;          cfi = &siloConfigType;
3944      } else if (configureZipl) {      } else if (configureZipl) {
3945          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3946        } else if (configureExtLinux) {
3947     cfi = &extlinuxConfigType;
3948     useextlinuxmenu=1;
3949      }      }
3950    
3951      if (!cfi) {      if (!cfi) {
3952            if (grub2FindConfig(&grub2ConfigType))
3953        cfi = &grub2ConfigType;
3954     else
3955        #ifdef __ia64__        #ifdef __ia64__
3956   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3957        #elif __powerpc__        #elif __powerpc__
3958   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3959        #elif __sparc__        #elif __sparc__
3960          cfi = &siloConfigType;              cfi = &siloConfigType;
3961        #elif __s390__        #elif __s390__
3962          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3963        #elif __s390x__        #elif __s390x__
3964          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3965        #else        #else
3966   cfi = &grubConfigType;      cfi = &grubConfigType;
3967        #endif        #endif
3968      }      }
3969    
3970      if (!grubConfig)      if (!grubConfig) {
3971   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3972        grubConfig = cfi->findConfig(cfi);
3973     if (!grubConfig)
3974        grubConfig = cfi->defaultConfig;
3975        }
3976    
3977      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3978    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
3979    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
3980        (defaultIndex >= 0))) {
3981   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3982    "specified option"));    "specified option"));
3983   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3993  int main(int argc, const char ** argv) {
3993      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3994   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3995   return 1;   return 1;
3996      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
3997    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
3998    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
3999   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4000   return 1;   return 1;
4001      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4019  int main(int argc, const char ** argv) {
4019   makeDefault = 1;   makeDefault = 1;
4020   defaultKernel = NULL;   defaultKernel = NULL;
4021      }      }
4022        else if (defaultKernel && (defaultIndex >= 0)) {
4023     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4024      "may not be used together\n"));
4025     return 1;
4026        }
4027    
4028      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4029   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4030   "is used\n"));   "is used\n"));
4031   return 1;   return 1;
4032      }      }
4033    
4034      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4035   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4036          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4037     && (defaultIndex == -1)) {
4038   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4039   return 1;   return 1;
4040      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4054  int main(int argc, const char ** argv) {
4054   bootPrefix = "";   bootPrefix = "";
4055      }      }
4056    
4057        if (!cfi->mbAllowExtraInitRds &&
4058     extraInitrdCount > 0) {
4059     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4060     return 1;
4061        }
4062    
4063      if (bootloaderProbe) {      if (bootloaderProbe) {
4064   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4065   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4066    
4067   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4068      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
4069        gconfig = readConfig(grub2config, &grub2ConfigType);
4070        if (!gconfig)
4071     gr2c = 1;
4072        else
4073     gr2c = checkForGrub2(gconfig);
4074     }
4075    
4076     const char *grubconfig = grubFindConfig(&grubConfigType);
4077     if (!access(grubconfig, F_OK)) {
4078        gconfig = readConfig(grubconfig, &grubConfigType);
4079      if (!gconfig)      if (!gconfig)
4080   grc = 1;   grc = 1;
4081      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4090  int main(int argc, const char ** argv) {
4090   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4091   }   }
4092    
4093   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4094        econfig = readConfig(eliloConfigType.defaultConfig,
4095     &eliloConfigType);
4096        if (!econfig)
4097     erc = 1;
4098        else
4099     erc = checkForElilo(econfig);
4100     }
4101    
4102     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4103        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4104        if (!lconfig)
4105     extrc = 1;
4106        else
4107     extrc = checkForExtLinux(lconfig);
4108     }
4109    
4110    
4111     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4112        yconfig = readConfig(yabootConfigType.defaultConfig,
4113     &yabootConfigType);
4114        if (!yconfig)
4115     yrc = 1;
4116        else
4117     yrc = checkForYaboot(yconfig);
4118     }
4119    
4120     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4121     erc == 1)
4122        return 1;
4123    
4124   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4125     if (gr2c == 2) printf("grub2\n");
4126   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4127     if (extrc == 2) printf("extlinux\n");
4128     if (yrc == 2) printf("yaboot\n");
4129     if (erc == 2) printf("elilo\n");
4130    
4131   return 0;   return 0;
4132      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4144  int main(int argc, const char ** argv) {
4144   if (!entry) return 0;   if (!entry) return 0;
4145   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4146    
4147   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4148   if (!line) return 0;   if (!line) return 0;
4149    
4150          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4152  int main(int argc, const char ** argv) {
4152                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4153    
4154   return 0;   return 0;
4155    
4156        } else if (displayDefaultTitle) {
4157     struct singleLine * line;
4158     struct singleEntry * entry;
4159    
4160     if (config->defaultImage == -1) return 0;
4161     entry = findEntryByIndex(config, config->defaultImage);
4162     if (!entry) return 0;
4163    
4164     if (!configureGrub2) {
4165      line = getLineByType(LT_TITLE, entry->lines);
4166      if (!line) return 0;
4167      printf("%s\n", line->elements[1].item);
4168    
4169     } else {
4170      char * title;
4171    
4172      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4173      line = getLineByType(LT_MENUENTRY, entry->lines);
4174      if (!line) return 0;
4175      title = grub2ExtractTitle(line);
4176      if (title)
4177        printf("%s\n", title);
4178     }
4179     return 0;
4180    
4181        } else if (displayDefaultIndex) {
4182            if (config->defaultImage == -1) return 0;
4183            printf("%i\n", config->defaultImage);
4184    
4185      } else if (kernelInfo)      } else if (kernelInfo)
4186   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4187    
# Line 2581  int main(int argc, const char ** argv) { Line 4193  int main(int argc, const char ** argv) {
4193      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4194      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4195      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4196      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4197      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4198      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4199                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4200        if (updateKernelPath && newKernelInitrd) {
4201                if (updateInitrd(config, updateKernelPath, bootPrefix,
4202                                 newKernelInitrd)) return 1;
4203        }
4204      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4205                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4206                         (const char **)extraInitrds, extraInitrdCount,
4207                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4208            
4209    
# Line 2597  int main(int argc, const char ** argv) { Line 4214  int main(int argc, const char ** argv) {
4214      }      }
4215    
4216      if (!outputFile)      if (!outputFile)
4217   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4218    
4219      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4220  }  }

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