Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC tags/grubby-8_20/grubby.c revision 2055 by niro, Wed Feb 20 14:02:40 2013 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  +   enum lineType_e ct = checkType;
1777                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1778                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1779                      break;   else if (checkType & LT_KERNEL)
1780              }      ct = checkType | LT_KERNEL_EFI;
1781                 line = getLineByType(ct, line);
1782              /* have to check multiboot lines too */   if (!line)
1783              if (entry->multiboot) {      break;  /* not found in this entry */
1784                  while (line && line->type != LT_MBMODULE) line = line->next;  
1785                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
1786                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
1787                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
1788                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
1789                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
1790                          break;   kernel + strlen(prefix)))
1791                  }   break;
1792              }   }
1793     if(line->type == LT_MENUENTRY &&
1794     !strcmp(line->elements[1].item, kernel))
1795        break;
1796        }
1797    
1798      i++;      /* make sure this entry has a kernel identifier; this skips
1799         * non-Linux boot entries (could find netbsd etc, though, which is
1800         * unfortunate)
1801         */
1802        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1803     break; /* found 'im! */
1804   }   }
1805    
1806   if (index) *index = i;   if (index) *index = i;
1807      }      }
1808    
     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);  
     }  
   
1809      return entry;      return entry;
1810  }  }
1811    
# Line 1200  void markRemovedImage(struct grubConfig Line 1884  void markRemovedImage(struct grubConfig
1884        const char * prefix) {        const char * prefix) {
1885      struct singleEntry * entry;      struct singleEntry * entry;
1886    
1887      if (!image) return;      if (!image)
1888     return;
1889    
1890        /* check and see if we're removing the default image */
1891        if (isdigit(*image)) {
1892     entry = findEntryByPath(cfg, image, prefix, NULL);
1893     if(entry)
1894        entry->skip = 1;
1895     return;
1896        }
1897    
1898      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1899   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1901  void markRemovedImage(struct grubConfig
1901    
1902  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1903       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1904       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1905      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1906      int i, j;      int i, j;
1907    
1908      if (newIsDefault) {      if (newIsDefault) {
1909   config->defaultImage = 0;   config->defaultImage = 0;
1910   return;   return;
1911        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1912     if (findEntryByIndex(config, index))
1913        config->defaultImage = index;
1914     else
1915        config->defaultImage = -1;
1916     return;
1917      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1918   i = 0;   i = 0;
1919   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1926  void setDefaultImage(struct grubConfig *
1926    
1927      /* 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
1928         changes */         changes */
1929      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1930     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1931        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1932        return;        return;
1933    
# Line 1286  void displayEntry(struct singleEntry * e Line 1986  void displayEntry(struct singleEntry * e
1986      char * root = NULL;      char * root = NULL;
1987      int i;      int i;
1988    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1989      printf("index=%d\n", index);      printf("index=%d\n", index);
1990    
1991      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1992        if (!line) {
1993            printf("non linux entry\n");
1994            return;
1995        }
1996    
1997        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
1998     printf("kernel=%s\n", line->elements[1].item);
1999        else
2000     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2001    
2002      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2003   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2014  void displayEntry(struct singleEntry * e
2014   }   }
2015   printf("\"\n");   printf("\"\n");
2016      } else {      } else {
2017   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2018   if (line) {   if (line) {
2019      char * s;      char * s;
2020    
# Line 1334  void displayEntry(struct singleEntry * e Line 2038  void displayEntry(struct singleEntry * e
2038      }      }
2039    
2040      if (!root) {      if (!root) {
2041   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2042   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2043      root=line->elements[1].item;      root=line->elements[1].item;
2044      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2053  void displayEntry(struct singleEntry * e
2053   printf("root=%s\n", s);   printf("root=%s\n", s);
2054      }      }
2055    
2056      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2057    
2058      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2059   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2060        printf("initrd=");
2061     else
2062        printf("initrd=%s", prefix);
2063    
2064   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2065      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2066   printf("\n");   printf("\n");
2067      }      }
2068    
2069        line = getLineByType(LT_TITLE, entry->lines);
2070        if (line) {
2071     printf("title=%s\n", line->elements[1].item);
2072        } else {
2073     char * title;
2074     line = getLineByType(LT_MENUENTRY, entry->lines);
2075     title = grub2ExtractTitle(line);
2076     if (title)
2077        printf("title=%s\n", title);
2078        }
2079    }
2080    
2081    int isSuseSystem(void) {
2082        const char * path;
2083        const static char default_path[] = "/etc/SuSE-release";
2084    
2085        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2086     path = default_path;
2087    
2088        if (!access(path, R_OK))
2089     return 1;
2090        return 0;
2091    }
2092    
2093    int isSuseGrubConf(const char * path) {
2094        FILE * grubConf;
2095        char * line = NULL;
2096        size_t len = 0, res = 0;
2097    
2098        grubConf = fopen(path, "r");
2099        if (!grubConf) {
2100            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2101     return 0;
2102        }
2103    
2104        while ((res = getline(&line, &len, grubConf)) != -1) {
2105     if (!strncmp(line, "setup", 5)) {
2106        fclose(grubConf);
2107        free(line);
2108        return 1;
2109     }
2110        }
2111    
2112        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2113          path);
2114    
2115        fclose(grubConf);
2116        free(line);
2117        return 0;
2118    }
2119    
2120    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2121        FILE * grubConf;
2122        char * line = NULL;
2123        size_t res = 0, len = 0;
2124    
2125        if (!path) return 1;
2126        if (!lbaPtr) return 1;
2127    
2128        grubConf = fopen(path, "r");
2129        if (!grubConf) return 1;
2130    
2131        while ((res = getline(&line, &len, grubConf)) != -1) {
2132     if (line[res - 1] == '\n')
2133        line[res - 1] = '\0';
2134     else if (len > res)
2135        line[res] = '\0';
2136     else {
2137        line = realloc(line, res + 1);
2138        line[res] = '\0';
2139     }
2140    
2141     if (!strncmp(line, "setup", 5)) {
2142        if (strstr(line, "--force-lba")) {
2143            *lbaPtr = 1;
2144        } else {
2145            *lbaPtr = 0;
2146        }
2147        dbgPrintf("lba: %i\n", *lbaPtr);
2148        break;
2149     }
2150        }
2151    
2152        free(line);
2153        fclose(grubConf);
2154        return 0;
2155    }
2156    
2157    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2158        FILE * grubConf;
2159        char * line = NULL;
2160        size_t res = 0, len = 0;
2161        char * lastParamPtr = NULL;
2162        char * secLastParamPtr = NULL;
2163        char installDeviceNumber = '\0';
2164        char * bounds = NULL;
2165    
2166        if (!path) return 1;
2167        if (!devicePtr) return 1;
2168    
2169        grubConf = fopen(path, "r");
2170        if (!grubConf) return 1;
2171    
2172        while ((res = getline(&line, &len, grubConf)) != -1) {
2173     if (strncmp(line, "setup", 5))
2174        continue;
2175    
2176     if (line[res - 1] == '\n')
2177        line[res - 1] = '\0';
2178     else if (len > res)
2179        line[res] = '\0';
2180     else {
2181        line = realloc(line, res + 1);
2182        line[res] = '\0';
2183     }
2184    
2185     lastParamPtr = bounds = line + res;
2186    
2187     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2188     while (!isspace(*lastParamPtr))
2189        lastParamPtr--;
2190     lastParamPtr++;
2191    
2192     secLastParamPtr = lastParamPtr - 2;
2193     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2194    
2195     if (lastParamPtr + 3 > bounds) {
2196        dbgPrintf("lastParamPtr going over boundary");
2197        fclose(grubConf);
2198        free(line);
2199        return 1;
2200     }
2201     if (!strncmp(lastParamPtr, "(hd", 3))
2202        lastParamPtr += 3;
2203     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2204    
2205     /*
2206     * Second last parameter will decide wether last parameter is
2207     * an IMAGE_DEVICE or INSTALL_DEVICE
2208     */
2209     while (!isspace(*secLastParamPtr))
2210        secLastParamPtr--;
2211     secLastParamPtr++;
2212    
2213     if (secLastParamPtr + 3 > bounds) {
2214        dbgPrintf("secLastParamPtr going over boundary");
2215        fclose(grubConf);
2216        free(line);
2217        return 1;
2218     }
2219     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2220     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2221        secLastParamPtr += 3;
2222        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2223        installDeviceNumber = *secLastParamPtr;
2224     } else {
2225        installDeviceNumber = *lastParamPtr;
2226     }
2227    
2228     *devicePtr = malloc(6);
2229     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2230     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2231     fclose(grubConf);
2232     free(line);
2233     return 0;
2234        }
2235    
2236        free(line);
2237        fclose(grubConf);
2238        return 1;
2239    }
2240    
2241    int grubGetBootFromDeviceMap(const char * device,
2242         char ** bootPtr) {
2243        FILE * deviceMap;
2244        char * line = NULL;
2245        size_t res = 0, len = 0;
2246        char * devicePtr;
2247        char * bounds = NULL;
2248        const char * path;
2249        const static char default_path[] = "/boot/grub/device.map";
2250    
2251        if (!device) return 1;
2252        if (!bootPtr) return 1;
2253    
2254        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2255     path = default_path;
2256    
2257        dbgPrintf("opening grub device.map file from: %s\n", path);
2258        deviceMap = fopen(path, "r");
2259        if (!deviceMap)
2260     return 1;
2261    
2262        while ((res = getline(&line, &len, deviceMap)) != -1) {
2263            if (!strncmp(line, "#", 1))
2264        continue;
2265    
2266     if (line[res - 1] == '\n')
2267        line[res - 1] = '\0';
2268     else if (len > res)
2269        line[res] = '\0';
2270     else {
2271        line = realloc(line, res + 1);
2272        line[res] = '\0';
2273     }
2274    
2275     devicePtr = line;
2276     bounds = line + res;
2277    
2278     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2279        devicePtr++;
2280     dbgPrintf("device: %s\n", devicePtr);
2281    
2282     if (!strncmp(devicePtr, device, strlen(device))) {
2283        devicePtr += strlen(device);
2284        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2285            devicePtr++;
2286    
2287        *bootPtr = strdup(devicePtr);
2288        break;
2289     }
2290        }
2291    
2292        free(line);
2293        fclose(deviceMap);
2294        return 0;
2295    }
2296    
2297    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2298        char * grubDevice;
2299    
2300        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2301     dbgPrintf("error looking for grub installation device\n");
2302        else
2303     dbgPrintf("grubby installation device: %s\n", grubDevice);
2304    
2305        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2306     dbgPrintf("error looking for grub boot device\n");
2307        else
2308     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2309    
2310        free(grubDevice);
2311        return 0;
2312    }
2313    
2314    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2315        /*
2316         * This SuSE grub configuration file at this location is not your average
2317         * grub configuration file, but instead the grub commands used to setup
2318         * grub on that system.
2319         */
2320        const char * path;
2321        const static char default_path[] = "/etc/grub.conf";
2322    
2323        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2324     path = default_path;
2325    
2326        if (!isSuseGrubConf(path)) return 1;
2327    
2328        if (lbaPtr) {
2329            *lbaPtr = 0;
2330            if (suseGrubConfGetLba(path, lbaPtr))
2331                return 1;
2332        }
2333    
2334        if (bootPtr) {
2335            *bootPtr = NULL;
2336            suseGrubConfGetBoot(path, bootPtr);
2337        }
2338    
2339        return 0;
2340  }  }
2341    
2342  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2346  int parseSysconfigGrub(int * lbaPtr, cha
2346      char * start;      char * start;
2347      char * param;      char * param;
2348    
2349      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2350      if (!in) return 1;      if (!in) return 1;
2351    
2352      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2387  int parseSysconfigGrub(int * lbaPtr, cha
2387  }  }
2388    
2389  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2390      char * boot;      char * boot = NULL;
2391      int lba;      int lba;
2392    
2393      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2394   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2395   if (boot) printf("boot=%s\n", boot);      free(boot);
2396        return;
2397     }
2398        } else {
2399            if (parseSysconfigGrub(&lba, &boot)) {
2400        free(boot);
2401        return;
2402     }
2403        }
2404    
2405        if (lba) printf("lba\n");
2406        if (boot) {
2407     printf("boot=%s\n", boot);
2408     free(boot);
2409      }      }
2410  }  }
2411    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2421  int displayInfo(struct grubConfig * conf
2421   return 1;   return 1;
2422      }      }
2423    
2424      /* 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
2425         be a better way */         be a better way */
2426      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2427   dumpSysconfigGrub();   dumpSysconfigGrub();
2428      } else {      } else {
2429   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2430   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2431      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2432   }   }
2433    
2434   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2435   if (line) printf("lba\n");   if (line) printf("lba\n");
2436      }      }
2437    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2446  int displayInfo(struct grubConfig * conf
2446      return 0;      return 0;
2447  }  }
2448    
2449    struct singleLine * addLineTmpl(struct singleEntry * entry,
2450     struct singleLine * tmplLine,
2451     struct singleLine * prevLine,
2452     const char * val,
2453     struct configFileInfo * cfi)
2454    {
2455        struct singleLine * newLine = lineDup(tmplLine);
2456    
2457        if (isEfi && cfi == &grub2ConfigType) {
2458     enum lineType_e old = newLine->type;
2459     newLine->type = preferredLineType(newLine->type, cfi);
2460     if (old != newLine->type)
2461        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2462        }
2463    
2464        if (val) {
2465     /* override the inherited value with our own.
2466     * This is a little weak because it only applies to elements[1]
2467     */
2468     if (newLine->numElements > 1)
2469        removeElement(newLine, 1);
2470     insertElement(newLine, val, 1, cfi);
2471    
2472     /* but try to keep the rootspec from the template... sigh */
2473     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2474        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2475        if (rootspec != NULL) {
2476     free(newLine->elements[1].item);
2477     newLine->elements[1].item =
2478        sdupprintf("%s%s", rootspec, val);
2479        }
2480     }
2481        }
2482    
2483        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2484          newLine->elements[0].item : "");
2485    
2486        if (!entry->lines) {
2487     /* first one on the list */
2488     entry->lines = newLine;
2489        } else if (prevLine) {
2490     /* add after prevLine */
2491     newLine->next = prevLine->next;
2492     prevLine->next = newLine;
2493        }
2494    
2495        return newLine;
2496    }
2497    
2498  /* val may be NULL */  /* val may be NULL */
2499  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2500       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2501       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2502       char * val) {       const char * val) {
2503      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2504      int i;      struct keywordTypes * kw;
2505        struct singleLine tmpl;
2506    
2507      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2508   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2509      if (type != LT_TITLE || !cfi->titleBracketed)       */
2510          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2511     /* we're doing a bracketed title (zipl) */
2512     tmpl.type = type;
2513     tmpl.numElements = 1;
2514     tmpl.elements = alloca(sizeof(*tmpl.elements));
2515     tmpl.elements[0].item = alloca(strlen(val)+3);
2516     sprintf(tmpl.elements[0].item, "[%s]", val);
2517     tmpl.elements[0].indent = "";
2518     val = NULL;
2519        } else if (type == LT_MENUENTRY) {
2520     char *lineend = "--class gnu-linux --class gnu --class os {";
2521     if (!val) {
2522        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2523        abort();
2524     }
2525     kw = getKeywordByType(type, cfi);
2526     if (!kw) {
2527        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2528        abort();
2529     }
2530     tmpl.indent = "";
2531     tmpl.type = type;
2532     tmpl.numElements = 3;
2533     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2534     tmpl.elements[0].item = kw->key;
2535     tmpl.elements[0].indent = alloca(2);
2536     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2537     tmpl.elements[1].item = (char *)val;
2538     tmpl.elements[1].indent = alloca(2);
2539     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2540     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2541     strcpy(tmpl.elements[2].item, lineend);
2542     tmpl.elements[2].indent = "";
2543        } else {
2544     kw = getKeywordByType(type, cfi);
2545     if (!kw) {
2546        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2547        abort();
2548     }
2549     tmpl.type = type;
2550     tmpl.numElements = val ? 2 : 1;
2551     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2552     tmpl.elements[0].item = kw->key;
2553     tmpl.elements[0].indent = alloca(2);
2554     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2555     if (val) {
2556        tmpl.elements[1].item = (char *)val;
2557        tmpl.elements[1].indent = "";
2558     }
2559        }
2560    
2561      /* 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
2562         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2563         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
2564         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2565         differently from the rest) */         differently from the rest) */
2566      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2567   line = entry->lines;   if (line->numElements) prev = line;
2568   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2569   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;  
2570      }      }
2571    
2572      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2573          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2574          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2575          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2576          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2577          line->elements[0].indent = malloc(2);   else
2578          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2579          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2580             if (menuEntry)
2581          if (val) {      tmpl.indent = "\t";
2582              line->elements[1].item = val;   else if (prev == entry->lines)
2583              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2584          }   else
2585      } 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("");  
2586      }      }
2587    
2588      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2589  }  }
2590    
2591  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2610  void removeLine(struct singleEntry * ent
2610      free(line);      free(line);
2611  }  }
2612    
2613    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2614    {
2615        struct singleLine newLine = {
2616     .indent = tmplLine->indent,
2617     .type = tmplLine->type,
2618     .next = tmplLine->next,
2619        };
2620        int firstQuotedItem = -1;
2621        int quoteLen = 0;
2622        int j;
2623        int element = 0;
2624        char *c;
2625    
2626        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2627        strcpy(c, tmplLine->elements[0].item);
2628        insertElement(&newLine, c, element++, cfi);
2629        free(c);
2630        c = NULL;
2631    
2632        for (j = 1; j < tmplLine->numElements; j++) {
2633     if (firstQuotedItem == -1) {
2634        quoteLen += strlen(tmplLine->elements[j].item);
2635        
2636        if (isquote(tmplLine->elements[j].item[0])) {
2637     firstQuotedItem = j;
2638            quoteLen += strlen(tmplLine->elements[j].indent);
2639        } else {
2640     c = malloc(quoteLen + 1);
2641     strcpy(c, tmplLine->elements[j].item);
2642     insertElement(&newLine, c, element++, cfi);
2643     free(c);
2644     quoteLen = 0;
2645        }
2646     } else {
2647        int itemlen = strlen(tmplLine->elements[j].item);
2648        quoteLen += itemlen;
2649        quoteLen += strlen(tmplLine->elements[j].indent);
2650        
2651        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2652     c = malloc(quoteLen + 1);
2653     c[0] = '\0';
2654     for (int i = firstQuotedItem; i < j+1; i++) {
2655        strcat(c, tmplLine->elements[i].item);
2656        strcat(c, tmplLine->elements[i].indent);
2657     }
2658     insertElement(&newLine, c, element++, cfi);
2659     free(c);
2660    
2661     firstQuotedItem = -1;
2662     quoteLen = 0;
2663        }
2664     }
2665        }
2666        while (tmplLine->numElements)
2667     removeElement(tmplLine, 0);
2668        if (tmplLine->elements)
2669     free(tmplLine->elements);
2670    
2671        tmplLine->numElements = newLine.numElements;
2672        tmplLine->elements = newLine.elements;
2673    }
2674    
2675    static void insertElement(struct singleLine * line,
2676      const char * item, int insertHere,
2677      struct configFileInfo * cfi)
2678    {
2679        struct keywordTypes * kw;
2680        char indent[2] = "";
2681    
2682        /* sanity check */
2683        if (insertHere > line->numElements) {
2684     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2685      insertHere, line->numElements);
2686     insertHere = line->numElements;
2687        }
2688    
2689        line->elements = realloc(line->elements, (line->numElements + 1) *
2690         sizeof(*line->elements));
2691        memmove(&line->elements[insertHere+1],
2692        &line->elements[insertHere],
2693        (line->numElements - insertHere) *
2694        sizeof(*line->elements));
2695        line->elements[insertHere].item = strdup(item);
2696    
2697        kw = getKeywordByType(line->type, cfi);
2698    
2699        if (line->numElements == 0) {
2700     indent[0] = '\0';
2701        } else if (insertHere == 0) {
2702     indent[0] = kw->nextChar;
2703        } else if (kw->separatorChar != '\0') {
2704     indent[0] = kw->separatorChar;
2705        } else {
2706     indent[0] = ' ';
2707        }
2708    
2709        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2710     /* move the end-of-line forward */
2711     line->elements[insertHere].indent =
2712        line->elements[insertHere-1].indent;
2713     line->elements[insertHere-1].indent = strdup(indent);
2714        } else {
2715     line->elements[insertHere].indent = strdup(indent);
2716        }
2717    
2718        line->numElements++;
2719    
2720        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2721          line->elements[0].item,
2722          line->elements[insertHere].item,
2723          line->elements[insertHere].indent,
2724          insertHere);
2725    }
2726    
2727    static void removeElement(struct singleLine * line, int removeHere) {
2728        int i;
2729    
2730        /* sanity check */
2731        if (removeHere >= line->numElements) return;
2732    
2733        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2734          removeHere, line->elements[removeHere].item);
2735    
2736        free(line->elements[removeHere].item);
2737    
2738        if (removeHere > 1) {
2739     /* previous argument gets this argument's post-indentation */
2740     free(line->elements[removeHere-1].indent);
2741     line->elements[removeHere-1].indent =
2742        line->elements[removeHere].indent;
2743        } else {
2744     free(line->elements[removeHere].indent);
2745        }
2746    
2747        /* now collapse the array, but don't bother to realloc smaller */
2748        for (i = removeHere; i < line->numElements - 1; i++)
2749     line->elements[i] = line->elements[i + 1];
2750    
2751        line->numElements--;
2752    }
2753    
2754  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2755      char * first, * second;      char * first, * second;
2756      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2773  int updateActualImage(struct grubConfig
2773      struct singleEntry * entry;      struct singleEntry * entry;
2774      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2775      int index = 0;      int index = 0;
2776      int i, j, k;      int i, k;
2777      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2778      const char ** arg;      const char ** arg;
2779      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2780      int firstElement;      int firstElement;
2781      int *usedElements, *usedArgs;      int *usedElements;
2782        int doreplace;
2783    
2784      if (!image) return 0;      if (!image) return 0;
2785    
# Line 1609  int updateActualImage(struct grubConfig Line 2806  int updateActualImage(struct grubConfig
2806   }   }
2807      }      }
2808    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2809    
2810      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2811   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2812    
2813      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2814   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2815    
2816      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2817    
2818      k = 0;   if (multibootArgs && !entry->multiboot)
2819      for (arg = newArgs; *arg; arg++)      continue;
2820          k++;  
2821      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2822     * LT_KERNELARGS, use that.  Otherwise use
2823     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2824     */
2825     if (useKernelArgs) {
2826        line = getLineByType(LT_KERNELARGS, entry->lines);
2827        if (!line) {
2828     /* no LT_KERNELARGS, need to add it */
2829     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2830           cfg->secondaryIndent, NULL);
2831        }
2832        firstElement = 1;
2833    
2834      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2835   index++;      line = getLineByType(LT_HYPER, entry->lines);
2836        if (!line) {
2837     /* a multiboot entry without LT_HYPER? */
2838     continue;
2839        }
2840        firstElement = 2;
2841    
2842   line = entry->lines;   } else {
2843   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
2844   if (!line) continue;      if (!line) {
2845   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2846     continue;
2847          if (entry->multiboot && !multibootArgs) {      }
2848              /* 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;  
2849   }   }
2850    
2851   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2852      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2853      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2854     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2855        /* this is a multiboot entry, make sure there's
2856         * -- on the args line
2857         */
2858        for (i = firstElement; i < line->numElements; i++) {
2859     if (!strcmp(line->elements[i].item, "--"))
2860        break;
2861        }
2862        if (i == line->numElements) {
2863     /* assume all existing args are kernel args,
2864     * prepend -- to make it official
2865     */
2866     insertElement(line, "--", firstElement, cfg->cfi);
2867     i = firstElement;
2868        }
2869        if (!multibootArgs) {
2870     /* kernel args start after the -- */
2871     firstElement = i + 1;
2872        }
2873     } else if (cfg->cfi->mbConcatArgs) {
2874        /* this is a non-multiboot entry, remove hyper args */
2875        for (i = firstElement; i < line->numElements; i++) {
2876     if (!strcmp(line->elements[i].item, "--"))
2877        break;
2878        }
2879        if (i < line->numElements) {
2880     /* remove args up to -- */
2881     while (strcmp(line->elements[firstElement].item, "--"))
2882        removeElement(line, firstElement);
2883     /* remove -- */
2884     removeElement(line, firstElement);
2885        }
2886   }   }
2887    
2888          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2889    
2890          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2891   for (arg = newArgs; *arg; arg++) {  
2892              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2893      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2894     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2895        !strcmp(line->elements[i].item, "--"))
2896     {
2897        /* reached the end of hyper args, insert here */
2898        doreplace = 0;
2899        break;  
2900     }
2901                  if (usedElements[i])                  if (usedElements[i])
2902                      continue;                      continue;
2903   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2904                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2905      break;      break;
2906                  }                  }
2907              }              }
     chptr = strchr(*arg, '=');  
2908    
2909      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2910   /* replace */   /* direct replacement */
2911   free(line->elements[i].item);   free(line->elements[i].item);
2912   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("");  
  }  
2913    
2914   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2915   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2916      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2917   /* append */   if (rootLine) {
2918   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2919   (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(" ");  
2920   } else {   } else {
2921      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2922         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2923   }   }
2924        }
2925    
2926   line->numElements++;      else {
2927     /* insert/append */
2928     insertElement(line, *arg, i, cfg->cfi);
2929     usedElements = realloc(usedElements, line->numElements *
2930           sizeof(*usedElements));
2931     memmove(&usedElements[i + 1], &usedElements[i],
2932     line->numElements - i - 1);
2933     usedElements[i] = 1;
2934    
2935   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2936     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2937     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2938   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2939      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2940      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2941   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2942   }   }
2943      }      }
             k++;  
2944   }   }
2945    
2946          free(usedElements);          free(usedElements);
2947    
  /* 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? */  
2948   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2949      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2950   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2951        !strcmp(line->elements[i].item, "--"))
2952        /* reached the end of hyper args, stop here */
2953        break;
2954     if (!argMatch(line->elements[i].item, *arg)) {
2955        removeElement(line, i);
2956      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;  
2957   }   }
2958        }
2959   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2960        if (useRoot && !strncmp(*arg, "root=", 5)) {
2961   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2962      line->elements[j - 1] = line->elements[j];   if (rootLine)
2963        removeLine(entry, rootLine);
  line->numElements--;  
2964      }      }
2965   }   }
2966    
# Line 1760  int updateActualImage(struct grubConfig Line 2971  int updateActualImage(struct grubConfig
2971   }   }
2972      }      }
2973    
     free(usedArgs);  
2974      free(newArgs);      free(newArgs);
2975      free(oldArgs);      free(oldArgs);
2976    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 2996  int updateImage(struct grubConfig * cfg,
2996      return rc;      return rc;
2997  }  }
2998    
2999    int updateInitrd(struct grubConfig * cfg, const char * image,
3000                     const char * prefix, const char * initrd) {
3001        struct singleEntry * entry;
3002        struct singleLine * line, * kernelLine, *endLine = NULL;
3003        int index = 0;
3004    
3005        if (!image) return 0;
3006    
3007        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3008            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3009            if (!kernelLine) continue;
3010    
3011            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3012            if (line)
3013                removeLine(entry, line);
3014            if (prefix) {
3015                int prefixLen = strlen(prefix);
3016                if (!strncmp(initrd, prefix, prefixLen))
3017                    initrd += prefixLen;
3018            }
3019     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3020     if (endLine)
3021        removeLine(entry, endLine);
3022            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3023     kernelLine->indent, initrd);
3024            if (!line)
3025        return 1;
3026     if (endLine) {
3027        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3028                if (!line)
3029     return 1;
3030     }
3031    
3032            break;
3033        }
3034    
3035        return 0;
3036    }
3037    
3038  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3039      int fd;      int fd;
3040      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3058  int checkDeviceBootloader(const char * d
3058      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3059   return 0;   return 0;
3060    
3061      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3062   offset = boot[2] + 2;   offset = boot[2] + 2;
3063      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3064   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3065      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3066   offset = boot[1] + 2;        offset = boot[1] + 2;
3067            /*
3068     * it looks like grub, when copying stage1 into the mbr, patches stage1
3069     * right after the JMP location, replacing other instructions such as
3070     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3071     * different bytes.
3072     */
3073          if ((bootSect[offset + 1] == NOOP_OPCODE)
3074      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3075     offset = offset + 3;
3076          }
3077      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3078   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3079      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3215  int checkForLilo(struct grubConfig * con
3215      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3216  }  }
3217    
3218    int checkForGrub2(struct grubConfig * config) {
3219        if (!access("/etc/grub.d/", R_OK))
3220     return 2;
3221    
3222        return 1;
3223    }
3224    
3225  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3226      int fd;      int fd;
3227      unsigned char bootSect[512];      unsigned char bootSect[512];
3228      char * boot;      char * boot;
3229        int onSuse = isSuseSystem();
3230    
3231      if (parseSysconfigGrub(NULL, &boot))  
3232   return 0;      if (onSuse) {
3233     if (parseSuseGrubConf(NULL, &boot))
3234        return 0;
3235        } else {
3236     if (parseSysconfigGrub(NULL, &boot))
3237        return 0;
3238        }
3239    
3240      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3241      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3249  int checkForGrub(struct grubConfig * con
3249      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3250   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3251   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3252     close(fd);
3253   return 1;   return 1;
3254      }      }
3255      close(fd);      close(fd);
3256    
3257        /* The more elaborate checks do not work on SuSE. The checks done
3258         * seem to be reasonble (at least for now), so just return success
3259         */
3260        if (onSuse)
3261     return 2;
3262    
3263      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3264  }  }
3265    
3266    int checkForExtLinux(struct grubConfig * config) {
3267        int fd;
3268        unsigned char bootSect[512];
3269        char * boot;
3270        char executable[] = "/boot/extlinux/extlinux";
3271    
3272        printf("entered: checkForExtLinux()\n");
3273    
3274        if (parseSysconfigGrub(NULL, &boot))
3275     return 0;
3276    
3277        /* assume grub is not installed -- not an error condition */
3278        if (!boot)
3279     return 0;
3280    
3281        fd = open(executable, O_RDONLY);
3282        if (fd < 0)
3283     /* this doesn't exist if grub hasn't been installed */
3284     return 0;
3285    
3286        if (read(fd, bootSect, 512) != 512) {
3287     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3288     executable, strerror(errno));
3289     return 1;
3290        }
3291        close(fd);
3292    
3293        return checkDeviceBootloader(boot, bootSect);
3294    }
3295    
3296    int checkForYaboot(struct grubConfig * config) {
3297        /*
3298         * This is a simplistic check that we consider good enough for own puporses
3299         *
3300         * If we were to properly check if yaboot is *installed* we'd need to:
3301         * 1) get the system boot device (LT_BOOT)
3302         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3303         *    the content on the boot device
3304         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3305         * 4) check again if binary and boot device contents match
3306         */
3307        if (!access("/etc/yaboot.conf", R_OK))
3308     return 2;
3309    
3310        return 1;
3311    }
3312    
3313    int checkForElilo(struct grubConfig * config) {
3314        if (!access("/etc/elilo.conf", R_OK))
3315     return 2;
3316    
3317        return 1;
3318    }
3319    
3320  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3321      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3322    
# Line 1994  static char * getRootSpecifier(char * st Line 3328  static char * getRootSpecifier(char * st
3328      return rootspec;      return rootspec;
3329  }  }
3330    
3331    static char * getInitrdVal(struct grubConfig * config,
3332       const char * prefix, struct singleLine *tmplLine,
3333       const char * newKernelInitrd,
3334       const char ** extraInitrds, int extraInitrdCount)
3335    {
3336        char *initrdVal, *end;
3337        int i;
3338        size_t totalSize;
3339        size_t prefixLen;
3340        char separatorChar;
3341    
3342        prefixLen = strlen(prefix);
3343        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3344    
3345        for (i = 0; i < extraInitrdCount; i++) {
3346     totalSize += sizeof(separatorChar);
3347     totalSize += strlen(extraInitrds[i]) - prefixLen;
3348        }
3349    
3350        initrdVal = end = malloc(totalSize);
3351    
3352        end = stpcpy (end, newKernelInitrd + prefixLen);
3353    
3354        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3355        for (i = 0; i < extraInitrdCount; i++) {
3356     const char *extraInitrd;
3357     int j;
3358    
3359     extraInitrd = extraInitrds[i] + prefixLen;
3360     /* Don't add entries that are already there */
3361     if (tmplLine != NULL) {
3362        for (j = 2; j < tmplLine->numElements; j++)
3363     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3364        break;
3365    
3366        if (j != tmplLine->numElements)
3367     continue;
3368     }
3369    
3370     *end++ = separatorChar;
3371     end = stpcpy(end, extraInitrd);
3372        }
3373    
3374        return initrdVal;
3375    }
3376    
3377  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3378           const char * prefix,           const char * prefix,
3379   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3380   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3381                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3382                     const char * newMBKernel, const char * newMBKernelArgs) {
3383      struct singleEntry * new;      struct singleEntry * new;
3384      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3385      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3386      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3387    
3388      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3389    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3413  int addNewKernel(struct grubConfig * con
3413      config->entries = new;      config->entries = new;
3414    
3415      /* copy/update from the template */      /* copy/update from the template */
3416      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3417        if (newKernelInitrd)
3418     needs |= NEED_INITRD;
3419      if (newMBKernel) {      if (newMBKernel) {
3420          needs |= KERNEL_MB;          needs |= NEED_MB;
3421          new->multiboot = 1;          new->multiboot = 1;
3422      }      }
3423    
3424      if (template) {      if (template) {
3425   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3426      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3427      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3428   indent = tmplLine->indent;   {
3429        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3430    
3431      /* skip comments */      /* skip comments */
3432      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3433      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3434      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3435    
3436      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3437      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3438        /* it's not a multiboot template and this is the kernel
3439              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3440                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3441                  struct singleLine *l;       */
3442                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3443     /* insert the hypervisor first */
3444                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3445                                    config->secondaryIndent,    tmplLine->indent,
3446                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3447                     /* set up for adding the kernel line */
3448                  tmplLine = lastLine;   free(tmplLine->indent);
3449                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3450                      new->lines = l;   needs &= ~NEED_MB;
3451                  } else {      }
3452                      newLine->next = l;      if (needs & NEED_KERNEL) {
3453                      newLine = l;   /* use addLineTmpl to preserve line elements,
3454                  }   * otherwise we could just call addLine.  Unfortunately
3455                  continue;   * this means making some changes to the template
3456              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3457                         template->multiboot && !new->multiboot) {   * change below.
3458                  continue; /* don't need multiboot kernel here */   */
3459              }   struct keywordTypes * mbm_kw =
3460        getKeywordByType(LT_MBMODULE, config->cfi);
3461      if (!new->lines) {   if (mbm_kw) {
3462   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3463   new->lines = newLine;      free(tmplLine->elements[0].item);
3464      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3465   newLine->next = malloc(sizeof(*newLine));   }
3466   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3467      }        newKernelPath + strlen(prefix), config->cfi);
3468     needs &= ~NEED_KERNEL;
3469        }
3470        if (needs & NEED_MB) { /* !mbHyperFirst */
3471     newLine = addLine(new, config->cfi, LT_HYPER,
3472      config->secondaryIndent,
3473      newMBKernel + strlen(prefix));
3474     needs &= ~NEED_MB;
3475        }
3476     } else if (needs & NEED_KERNEL) {
3477        newLine = addLineTmpl(new, tmplLine, newLine,
3478      newKernelPath + strlen(prefix), config->cfi);
3479        needs &= ~NEED_KERNEL;
3480     }
3481    
3482        } else if (tmplLine->type == LT_HYPER &&
3483           tmplLine->numElements >= 2) {
3484     if (needs & NEED_MB) {
3485        newLine = addLineTmpl(new, tmplLine, newLine,
3486      newMBKernel + strlen(prefix), config->cfi);
3487        needs &= ~NEED_MB;
3488     }
3489    
3490      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3491      newLine->next = NULL;         tmplLine->numElements >= 2) {
3492      newLine->type = tmplLine->type;   if (new->multiboot) {
3493      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3494      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3495      newLine->numElements);        newKernelPath +
3496      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3497   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3498   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3499   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3500      }   char *initrdVal;
3501     initrdVal = getInitrdVal(config, prefix, tmplLine,
3502              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3503      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3504                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3505                  if (!template->multiboot) {        initrdVal, config->cfi);
3506                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3507                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3508                  } else {      }
3509                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3510                      repl = newMBKernel;      /* template is multi but new is not,
3511                  }       * insert the kernel in the first module slot
3512                  if (new->multiboot && !template->multiboot) {       */
3513                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3514                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3515                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3516                  }   strdup(getKeywordByType(tmplLine->type,
3517   free(newLine->elements[1].item);   config->cfi)->key);
3518                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3519                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3520                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3521                                                             rootspec,      needs &= ~NEED_KERNEL;
3522                                                             repl +   } else if (needs & NEED_INITRD) {
3523                                                             strlen(prefix));      char *initrdVal;
3524                  } else {      /* template is multi but new is not,
3525                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3526                                                         strlen(prefix));       */
3527                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3528              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3529                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3530                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3531                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3532                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3533                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3534                      newLine->type = LT_KERNEL;      free(initrdVal);
3535                  }      needs &= ~NEED_INITRD;
3536   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;  
3537    
3538   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3539      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3540      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3541        config->cfi->mbInitRdIsModule) {
3542        /* make sure we don't insert the module initrd
3543         * before the module kernel... if we don't do it here,
3544         * it will be inserted following the template.
3545         */
3546        if (!needs & NEED_KERNEL) {
3547     char *initrdVal;
3548    
3549     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3550     newLine = addLine(new, config->cfi, LT_MBMODULE,
3551      config->secondaryIndent,
3552      initrdVal);
3553     free(initrdVal);
3554     needs &= ~NEED_INITRD;
3555        }
3556     } else if (needs & NEED_INITRD) {
3557        char *initrdVal;
3558        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3559        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3560        free(initrdVal);
3561        needs &= ~NEED_INITRD;
3562   }   }
3563    
3564   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3565   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3566   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3567     char *nkt = malloc(strlen(newKernelTitle)+3);
3568     strcpy(nkt, "'");
3569     strcat(nkt, newKernelTitle);
3570     strcat(nkt, "'");
3571     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3572     free(nkt);
3573     needs &= ~NEED_TITLE;
3574      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3575                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3576                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3577                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3578                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3579                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3580                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3581                                             newLine->numElements);     config->cfi->titleBracketed) {
3582        /* addLineTmpl doesn't handle titleBracketed */
3583                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3584                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3585                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3586                  newLine->numElements = 1;   }
3587              }      } else if (tmplLine->type == LT_ECHO) {
3588        requote(tmplLine, config->cfi);
3589        static const char *prefix = "'Loading ";
3590        if (tmplLine->numElements > 1 &&
3591        strstr(tmplLine->elements[1].item, prefix) &&
3592        masterLine->next &&
3593        iskernel(masterLine->next->type)) {
3594     char *newTitle = malloc(strlen(prefix) +
3595     strlen(newKernelTitle) + 2);
3596    
3597     strcpy(newTitle, prefix);
3598     strcat(newTitle, newKernelTitle);
3599     strcat(newTitle, "'");
3600     newLine = addLine(new, config->cfi, LT_ECHO,
3601     tmplLine->indent, newTitle);
3602     free(newTitle);
3603        } else {
3604     /* pass through other lines from the template */
3605     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3606     config->cfi);
3607        }
3608        } else {
3609     /* pass through other lines from the template */
3610     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3611        }
3612   }   }
3613    
3614      } else {      } else {
3615   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3616      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3617     */
3618     switch (config->cfi->entryStart) {
3619        case LT_KERNEL:
3620        case LT_KERNEL_EFI:
3621     if (new->multiboot && config->cfi->mbHyperFirst) {
3622        /* fall through to LT_HYPER */
3623     } else {
3624        newLine = addLine(new, config->cfi,
3625              preferredLineType(LT_KERNEL, config->cfi),
3626          config->primaryIndent,
3627          newKernelPath + strlen(prefix));
3628        needs &= ~NEED_KERNEL;
3629        break;
3630     }
3631    
3632        case LT_HYPER:
3633     newLine = addLine(new, config->cfi, LT_HYPER,
3634      config->primaryIndent,
3635      newMBKernel + strlen(prefix));
3636     needs &= ~NEED_MB;
3637   break;   break;
         }  
3638    
3639   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3640      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3641       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3642       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3643      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3644       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3645      default:        config->primaryIndent, nkt);
3646                  /* zipl strikes again */   free(nkt);
3647                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3648                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3649                      chptr = newKernelTitle;   break;
3650                      type = LT_TITLE;      }
3651                      break;      case LT_TITLE:
3652                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3653                      abort();   char * templabel;
3654                  }   int x = 0, y = 0;
3655   }  
3656     templabel = strdup(newKernelTitle);
3657     while( templabel[x]){
3658     if( templabel[x] == ' ' ){
3659     y = x;
3660     while( templabel[y] ){
3661     templabel[y] = templabel[y+1];
3662     y++;
3663     }
3664     }
3665     x++;
3666     }
3667     newLine = addLine(new, config->cfi, LT_TITLE,
3668      config->primaryIndent, templabel);
3669     free(templabel);
3670     }else{
3671     newLine = addLine(new, config->cfi, LT_TITLE,
3672      config->primaryIndent, newKernelTitle);
3673     }
3674     needs &= ~NEED_TITLE;
3675     break;
3676    
3677   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3678   new->lines = newLine;   abort();
3679     }
3680      }      }
3681    
3682      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3683          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3684              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3685                                config->secondaryIndent,       */
3686                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3687          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3688              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3689                                config->secondaryIndent,    newKernelTitle);
3690                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3691          /* don't need to check for title as it's guaranteed to have been      }
3692           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3693           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3694          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3695              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3696                                config->secondaryIndent,   needs &= ~NEED_MB;
3697                                newKernelInitrd + strlen(prefix));      }
3698      } else {      if (needs & NEED_KERNEL) {
3699          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3700              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3701                                config->secondaryIndent,        config->cfi))
3702                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3703          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3704              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3705                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3706                                newKernelTitle);   needs &= ~NEED_KERNEL;
3707          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3708              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3709                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3710                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3711      newMBKernel + strlen(prefix));
3712     needs &= ~NEED_MB;
3713        }
3714        if (needs & NEED_INITRD) {
3715     char *initrdVal;
3716     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3717     newLine = addLine(new, config->cfi,
3718      (new->multiboot && getKeywordByType(LT_MBMODULE,
3719          config->cfi))
3720       ? LT_MBMODULE
3721       : preferredLineType(LT_INITRD, config->cfi),
3722      config->secondaryIndent,
3723      initrdVal);
3724     free(initrdVal);
3725     needs &= ~NEED_INITRD;
3726        }
3727        if (needs & NEED_END) {
3728     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3729     config->secondaryIndent, NULL);
3730     needs &= ~NEED_END;
3731        }
3732    
3733        if (needs) {
3734     printf(_("grubby: needs=%d, aborting\n"), needs);
3735     abort();
3736      }      }
3737    
3738      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3741  int addNewKernel(struct grubConfig * con
3741      return 0;      return 0;
3742  }  }
3743    
3744    static void traceback(int signum)
3745    {
3746        void *array[40];
3747        size_t size;
3748    
3749        signal(SIGSEGV, SIG_DFL);
3750        memset(array, '\0', sizeof (array));
3751        size = backtrace(array, 40);
3752    
3753        fprintf(stderr, "grubby recieved SIGSEGV!  Backtrace (%ld):\n",
3754                (unsigned long)size);
3755        backtrace_symbols_fd(array, size, STDERR_FILENO);
3756        exit(1);
3757    }
3758    
3759  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3760      poptContext optCon;      poptContext optCon;
3761      char * grubConfig = NULL;      const char * grubConfig = NULL;
3762      char * outputFile = NULL;      char * outputFile = NULL;
3763      int arg = 0;      int arg = 0;
3764      int flags = 0;      int flags = 0;
3765      int badImageOkay = 0;      int badImageOkay = 0;
3766        int configureGrub2 = 0;
3767      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3768      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3769        int configureExtLinux = 0;
3770      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3771        int extraInitrdCount = 0;
3772      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3773      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3774      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3784  int main(int argc, const char ** argv) {
3784      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3785      char * removeArgs = NULL;      char * removeArgs = NULL;
3786      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3787        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3788      const char * chptr = NULL;      const char * chptr = NULL;
3789      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3790      struct grubConfig * config;      struct grubConfig * config;
3791      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3792      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3793      int displayDefault = 0;      int displayDefault = 0;
3794        int displayDefaultIndex = 0;
3795        int displayDefaultTitle = 0;
3796        int defaultIndex = -1;
3797      struct poptOption options[] = {      struct poptOption options[] = {
3798   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3799      _("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 3811  int main(int argc, const char ** argv) {
3811   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3812      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3813      _("bootfs") },      _("bootfs") },
3814  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3815   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3816      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3817  #endif  #endif
3818   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3819      _("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 3824  int main(int argc, const char ** argv) {
3824        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3825        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3826        "template"), NULL },        "template"), NULL },
3827     { "debug", 0, 0, &debug, 0,
3828        _("print debugging information for failures") },
3829   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3830      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3831     { "default-index", 0, 0, &displayDefaultIndex, 0,
3832        _("display the index of the default kernel") },
3833     { "default-title", 0, 0, &displayDefaultTitle, 0,
3834        _("display the title of the default kernel") },
3835   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3836      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3837     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
3838        _("force grub2 stanzas to use efi") },
3839     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3840        _("configure extlinux bootloader (from syslinux)") },
3841   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3842      _("configure grub bootloader") },      _("configure grub bootloader") },
3843     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3844        _("configure grub2 bootloader") },
3845   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3846      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3847      _("kernel-path") },      _("kernel-path") },
3848   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3849      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3850     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3851        _("auxilliary initrd image for things other than the new kernel"), _("initrd-path") },
3852   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3853      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3854   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3868  int main(int argc, const char ** argv) {
3868   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3869      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3870        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3871     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3872        _("make the given entry index the default entry"),
3873        _("entry-index") },
3874   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3875      _("configure silo bootloader") },      _("configure silo bootloader") },
3876   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3888  int main(int argc, const char ** argv) {
3888   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3889      };      };
3890    
3891        useextlinuxmenu=0;
3892    
3893        signal(SIGSEGV, traceback);
3894    
3895      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3896      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3897    
# Line 2391  int main(int argc, const char ** argv) { Line 3901  int main(int argc, const char ** argv) {
3901      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3902      exit(0);      exit(0);
3903      break;      break;
3904      case 'i':
3905        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3906         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3907        } else {
3908     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3909     return 1;
3910        }
3911        break;
3912   }   }
3913      }      }
3914    
# Line 2406  int main(int argc, const char ** argv) { Line 3924  int main(int argc, const char ** argv) {
3924   return 1;   return 1;
3925      }      }
3926    
3927      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3928   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3929     configureExtLinux ) > 1) {
3930   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3931   return 1;   return 1;
3932      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3933   fprintf(stderr,   fprintf(stderr,
3934      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3935   return 1;   return 1;
3936        } else if (configureGrub2) {
3937     cfi = &grub2ConfigType;
3938      } else if (configureLilo) {      } else if (configureLilo) {
3939   cfi = &liloConfigType;   cfi = &liloConfigType;
3940      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3947  int main(int argc, const char ** argv) {
3947          cfi = &siloConfigType;          cfi = &siloConfigType;
3948      } else if (configureZipl) {      } else if (configureZipl) {
3949          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3950        } else if (configureExtLinux) {
3951     cfi = &extlinuxConfigType;
3952     useextlinuxmenu=1;
3953      }      }
3954    
3955      if (!cfi) {      if (!cfi) {
3956            if (grub2FindConfig(&grub2ConfigType))
3957        cfi = &grub2ConfigType;
3958     else
3959        #ifdef __ia64__        #ifdef __ia64__
3960   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3961        #elif __powerpc__        #elif __powerpc__
3962   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3963        #elif __sparc__        #elif __sparc__
3964          cfi = &siloConfigType;              cfi = &siloConfigType;
3965        #elif __s390__        #elif __s390__
3966          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3967        #elif __s390x__        #elif __s390x__
3968          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3969        #else        #else
3970   cfi = &grubConfigType;      cfi = &grubConfigType;
3971        #endif        #endif
3972      }      }
3973    
3974      if (!grubConfig)      if (!grubConfig) {
3975   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3976        grubConfig = cfi->findConfig(cfi);
3977     if (!grubConfig)
3978        grubConfig = cfi->defaultConfig;
3979        }
3980    
3981      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3982    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
3983    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
3984        (defaultIndex >= 0))) {
3985   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3986    "specified option"));    "specified option"));
3987   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 3997  int main(int argc, const char ** argv) {
3997      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
3998   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
3999   return 1;   return 1;
4000      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4001    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4002    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4003   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4004   return 1;   return 1;
4005      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4023  int main(int argc, const char ** argv) {
4023   makeDefault = 1;   makeDefault = 1;
4024   defaultKernel = NULL;   defaultKernel = NULL;
4025      }      }
4026        else if (defaultKernel && (defaultIndex >= 0)) {
4027     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4028      "may not be used together\n"));
4029     return 1;
4030        }
4031    
4032      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4033   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4034   "is used\n"));   "is used\n"));
4035   return 1;   return 1;
4036      }      }
4037    
4038      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4039   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4040          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4041     && (defaultIndex == -1)) {
4042   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4043   return 1;   return 1;
4044      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4058  int main(int argc, const char ** argv) {
4058   bootPrefix = "";   bootPrefix = "";
4059      }      }
4060    
4061        if (!cfi->mbAllowExtraInitRds &&
4062     extraInitrdCount > 0) {
4063     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4064     return 1;
4065        }
4066    
4067      if (bootloaderProbe) {      if (bootloaderProbe) {
4068   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4069   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4070    
4071   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4072      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
4073        gconfig = readConfig(grub2config, &grub2ConfigType);
4074        if (!gconfig)
4075     gr2c = 1;
4076        else
4077     gr2c = checkForGrub2(gconfig);
4078     }
4079    
4080     const char *grubconfig = grubFindConfig(&grubConfigType);
4081     if (!access(grubconfig, F_OK)) {
4082        gconfig = readConfig(grubconfig, &grubConfigType);
4083      if (!gconfig)      if (!gconfig)
4084   grc = 1;   grc = 1;
4085      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4094  int main(int argc, const char ** argv) {
4094   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4095   }   }
4096    
4097   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4098        econfig = readConfig(eliloConfigType.defaultConfig,
4099     &eliloConfigType);
4100        if (!econfig)
4101     erc = 1;
4102        else
4103     erc = checkForElilo(econfig);
4104     }
4105    
4106     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4107        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4108        if (!lconfig)
4109     extrc = 1;
4110        else
4111     extrc = checkForExtLinux(lconfig);
4112     }
4113    
4114    
4115     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4116        yconfig = readConfig(yabootConfigType.defaultConfig,
4117     &yabootConfigType);
4118        if (!yconfig)
4119     yrc = 1;
4120        else
4121     yrc = checkForYaboot(yconfig);
4122     }
4123    
4124     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4125     erc == 1)
4126        return 1;
4127    
4128   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4129     if (gr2c == 2) printf("grub2\n");
4130   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4131     if (extrc == 2) printf("extlinux\n");
4132     if (yrc == 2) printf("yaboot\n");
4133     if (erc == 2) printf("elilo\n");
4134    
4135   return 0;   return 0;
4136      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4148  int main(int argc, const char ** argv) {
4148   if (!entry) return 0;   if (!entry) return 0;
4149   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4150    
4151   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4152   if (!line) return 0;   if (!line) return 0;
4153    
4154          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4156  int main(int argc, const char ** argv) {
4156                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4157    
4158   return 0;   return 0;
4159    
4160        } else if (displayDefaultTitle) {
4161     struct singleLine * line;
4162     struct singleEntry * entry;
4163    
4164     if (config->defaultImage == -1) return 0;
4165     entry = findEntryByIndex(config, config->defaultImage);
4166     if (!entry) return 0;
4167    
4168     if (!configureGrub2) {
4169      line = getLineByType(LT_TITLE, entry->lines);
4170      if (!line) return 0;
4171      printf("%s\n", line->elements[1].item);
4172    
4173     } else {
4174      char * title;
4175    
4176      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4177      line = getLineByType(LT_MENUENTRY, entry->lines);
4178      if (!line) return 0;
4179      title = grub2ExtractTitle(line);
4180      if (title)
4181        printf("%s\n", title);
4182     }
4183     return 0;
4184    
4185        } else if (displayDefaultIndex) {
4186            if (config->defaultImage == -1) return 0;
4187            printf("%i\n", config->defaultImage);
4188    
4189      } else if (kernelInfo)      } else if (kernelInfo)
4190   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4191    
# Line 2581  int main(int argc, const char ** argv) { Line 4197  int main(int argc, const char ** argv) {
4197      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4198      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4199      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4200      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4201      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4202      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4203                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4204        if (updateKernelPath && newKernelInitrd) {
4205                if (updateInitrd(config, updateKernelPath, bootPrefix,
4206                                 newKernelInitrd)) return 1;
4207        }
4208      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4209                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4210                         (const char **)extraInitrds, extraInitrdCount,
4211                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4212            
4213    
# Line 2597  int main(int argc, const char ** argv) { Line 4218  int main(int argc, const char ** argv) {
4218      }      }
4219    
4220      if (!outputFile)      if (!outputFile)
4221   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4222    
4223      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4224  }  }

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