Magellan Linux

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

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

trunk/mkinitrd-magellan/grubby/grubby.c revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC trunk/grubby/grubby.c revision 2058 by niro, Wed Feb 20 14:06:30 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 caseInsensitive;
142      int defaultIsIndex;      int defaultIsIndex;
143        int defaultIsVariable;
144      int defaultSupportSaved;      int defaultSupportSaved;
145      enum lineType_e entrySeparator;      enum lineType_e entryStart;
146        enum lineType_e entryEnd;
147      int needsBootPrefix;      int needsBootPrefix;
148      int argsInQuotes;      int argsInQuotes;
149      int maxTitleLength;      int maxTitleLength;
150      int titleBracketed;      int titleBracketed;
151        int titlePosition;
152        int mbHyperFirst;
153        int mbInitRdIsModule;
154        int mbConcatArgs;
155        int mbAllowExtraInitRds;
156  };  };
157    
158  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 161  struct keywordTypes grubKeywords[] = {
161      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
162      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
163      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
164      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
165      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
166        { "kernel",     LT_HYPER,       ' ' },
167      { NULL,    0, 0 },      { NULL,    0, 0 },
168  };  };
169    
170    const char *grubFindConfig(struct configFileInfo *cfi) {
171        static const char *configFiles[] = {
172     "/boot/grub/grub.conf",
173     "/boot/grub/menu.lst",
174     "/etc/grub.conf",
175     NULL
176        };
177        static int i = -1;
178    
179        if (i == -1) {
180     for (i = 0; configFiles[i] != NULL; i++) {
181        dbgPrintf("Checking \"%s\": ", configFiles[i]);
182        if (!access(configFiles[i], R_OK)) {
183     dbgPrintf("found\n");
184     return configFiles[i];
185        }
186        dbgPrintf("not found\n");
187     }
188        }
189        return configFiles[i];
190    }
191    
192  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
193      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
194      grubKeywords,    /* keywords */      .keywords = grubKeywords,
195      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
196      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
197      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
198      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
199      0,    /* argsInQuotes */      .mbHyperFirst = 1,
200      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
201      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
202    };
203    
204    struct keywordTypes grub2Keywords[] = {
205        { "menuentry",  LT_MENUENTRY,   ' ' },
206        { "}",          LT_ENTRY_END,   ' ' },
207        { "echo",       LT_ECHO,        ' ' },
208        { "set",        LT_SET_VARIABLE,' ', '=' },
209        { "root",       LT_BOOTROOT,    ' ' },
210        { "default",    LT_DEFAULT,     ' ' },
211        { "fallback",   LT_FALLBACK,    ' ' },
212        { "linux",      LT_KERNEL,      ' ' },
213        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
214        { "initrd",     LT_INITRD,      ' ', ' ' },
215        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
216        { "module",     LT_MBMODULE,    ' ' },
217        { "kernel",     LT_HYPER,       ' ' },
218        { NULL, 0, 0 },
219    };
220    
221    const char *grub2FindConfig(struct configFileInfo *cfi) {
222        static const char *configFiles[] = {
223     "/boot/grub/grub-efi.cfg",
224     "/boot/grub/grub.cfg",
225     NULL
226        };
227        static int i = -1;
228        static const char *grub_cfg = "/boot/grub/grub.cfg";
229    
230        if (i == -1) {
231     for (i = 0; configFiles[i] != NULL; i++) {
232        dbgPrintf("Checking \"%s\": ", configFiles[i]);
233        if (!access(configFiles[i], R_OK)) {
234     dbgPrintf("found\n");
235     return configFiles[i];
236        }
237     }
238        }
239    
240        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
241         * that isn't in grub1, and if it exists, return the config file path
242         * that they use. */
243        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
244     dbgPrintf("found\n");
245     return grub_cfg;
246        }
247    
248        dbgPrintf("not found\n");
249        return configFiles[i];
250    }
251    
252    int sizeOfSingleLine(struct singleLine * line) {
253      int count = 0;
254    
255      for (int i = 0; i < line->numElements; i++) {
256        int indentSize = 0;
257    
258        count = count + strlen(line->elements[i].item);
259    
260        indentSize = strlen(line->elements[i].indent);
261        if (indentSize > 0)
262          count = count + indentSize;
263        else
264          /* be extra safe and add room for whitespaces */
265          count = count + 1;
266      }
267    
268      /* room for trailing terminator */
269      count = count + 1;
270    
271      return count;
272    }
273    
274    static int isquote(char q)
275    {
276        if (q == '\'' || q == '\"')
277     return 1;
278        return 0;
279    }
280    
281    static int iskernel(enum lineType_e type) {
282        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
283    }
284    
285    static int isinitrd(enum lineType_e type) {
286        return (type == LT_INITRD || type == LT_INITRD_EFI);
287    }
288    
289    char *grub2ExtractTitle(struct singleLine * line) {
290        char * current;
291        char * current_indent;
292        int current_len;
293        int current_indent_len;
294        int i;
295    
296        /* bail out if line does not start with menuentry */
297        if (strcmp(line->elements[0].item, "menuentry"))
298          return NULL;
299    
300        i = 1;
301        current = line->elements[i].item;
302        current_len = strlen(current);
303    
304        /* if second word is quoted, strip the quotes and return single word */
305        if (isquote(*current) && isquote(current[current_len - 1])) {
306     char *tmp;
307    
308     tmp = strdup(current);
309     *(tmp + current_len - 1) = '\0';
310     return ++tmp;
311        }
312    
313        /* if no quotes, return second word verbatim */
314        if (!isquote(*current))
315     return current;
316    
317        /* second element start with a quote, so we have to find the element
318         * whose last character is also quote (assuming it's the closing one) */
319        int resultMaxSize;
320        char * result;
321        
322        resultMaxSize = sizeOfSingleLine(line);
323        result = malloc(resultMaxSize);
324        snprintf(result, resultMaxSize, "%s", ++current);
325        
326        i++;
327        for (; i < line->numElements; ++i) {
328     current = line->elements[i].item;
329     current_len = strlen(current);
330     current_indent = line->elements[i].indent;
331     current_indent_len = strlen(current_indent);
332    
333     strncat(result, current_indent, current_indent_len);
334     if (!isquote(current[current_len-1])) {
335        strncat(result, current, current_len);
336     } else {
337        strncat(result, current, current_len - 1);
338        break;
339     }
340        }
341        return result;
342    }
343    
344    struct configFileInfo grub2ConfigType = {
345        .findConfig = grub2FindConfig,
346        .keywords = grub2Keywords,
347        .defaultIsIndex = 1,
348        .defaultSupportSaved = 1,
349        .defaultIsVariable = 1,
350        .entryStart = LT_MENUENTRY,
351        .entryEnd = LT_ENTRY_END,
352        .titlePosition = 1,
353        .needsBootPrefix = 1,
354        .mbHyperFirst = 1,
355        .mbInitRdIsModule = 1,
356        .mbAllowExtraInitRds = 1,
357  };  };
358    
359  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 387  struct keywordTypes yabootKeywords[] = {
387      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
388      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
389      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
390      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
391      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
392      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
393      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 407  struct keywordTypes liloKeywords[] = {
407      { NULL,    0, 0 },      { NULL,    0, 0 },
408  };  };
409    
410    struct keywordTypes eliloKeywords[] = {
411        { "label",    LT_TITLE,    '=' },
412        { "root",    LT_ROOT,    '=' },
413        { "default",    LT_DEFAULT,    '=' },
414        { "image",    LT_KERNEL,    '=' },
415        { "initrd",    LT_INITRD,    '=' },
416        { "append",    LT_KERNELARGS,  '=' },
417        { "vmm",    LT_HYPER,       '=' },
418        { NULL,    0, 0 },
419    };
420    
421  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
422      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
423      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 439  struct keywordTypes ziplKeywords[] = {
439      { NULL,         0, 0 },      { NULL,         0, 0 },
440  };  };
441    
442    struct keywordTypes extlinuxKeywords[] = {
443        { "label",    LT_TITLE,    ' ' },
444        { "root",    LT_ROOT,    ' ' },
445        { "default",    LT_DEFAULT,    ' ' },
446        { "kernel",    LT_KERNEL,    ' ' },
447        { "initrd",    LT_INITRD,      ' ', ',' },
448        { "append",    LT_KERNELARGS,  ' ' },
449        { "prompt",     LT_UNKNOWN,     ' ' },
450        { NULL,    0, 0 },
451    };
452    int useextlinuxmenu;
453  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
454      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
455      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
456      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
457      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
458      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
459      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
460  };  };
461    
462  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
463      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
464      liloKeywords,    /* keywords */      .keywords = liloKeywords,
465      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
466      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
467      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
468  };  };
469    
470  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
471      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
472      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
473      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
474      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
475      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
476      1,    /* needsBootPrefix */      .maxTitleLength = 15,
477      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
478  };  };
479    
480  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
481      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
482      siloKeywords,    /* keywords */      .keywords = siloKeywords,
483      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
484      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
485      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
486      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
487  };  };
488    
489  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
490      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
491      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
492      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
493      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
494      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
495      0,    /* needsBootPrefix */  };
496      1,    /* argsInQuotes */  
497      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
498      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
499        .keywords = extlinuxKeywords,
500        .caseInsensitive = 1,
501        .entryStart = LT_TITLE,
502        .needsBootPrefix = 1,
503        .maxTitleLength = 255,
504        .mbAllowExtraInitRds = 1,
505  };  };
506    
507  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 516  struct grubConfig {
516      struct configFileInfo * cfi;      struct configFileInfo * cfi;
517  };  };
518    
519    blkid_cache blkid;
520    
521  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
522  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
523       const char * path, const char * prefix,       const char * path, const char * prefix,
524       int * index);       int * index);
 static char * strndup(char * from, int len);  
525  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
526  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
527    struct singleLine * lineDup(struct singleLine * line);
528  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
529  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
530       struct configFileInfo * cfi);       struct configFileInfo * cfi);
531  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
532         struct configFileInfo * cfi);         struct configFileInfo * cfi);
533  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
534    static void requote(struct singleLine *line, struct configFileInfo * cfi);
535  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
536      char * to;    const char * item, int insertHere,
537      struct configFileInfo * cfi);
538      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
539      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
540      to[len] = '\0';        struct configFileInfo * cfi);
541    static enum lineType_e getTypeByKeyword(char * keyword,
542      return to;   struct configFileInfo * cfi);
543  }  static struct singleLine * getLineByType(enum lineType_e type,
544     struct singleLine * line);
545    static int checkForExtLinux(struct grubConfig * config);
546    struct singleLine * addLineTmpl(struct singleEntry * entry,
547                                    struct singleLine * tmplLine,
548                                    struct singleLine * prevLine,
549                                    const char * val,
550     struct configFileInfo * cfi);
551    struct singleLine *  addLine(struct singleEntry * entry,
552                                 struct configFileInfo * cfi,
553                                 enum lineType_e type, char * defaultIndent,
554                                 const char * val);
555    
556  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
557  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 586  static char * sdupprintf(const char *for
586      return buf;      return buf;
587  }  }
588    
589    static enum lineType_e preferredLineType(enum lineType_e type,
590     struct configFileInfo *cfi) {
591        if (isEfi && cfi == &grub2ConfigType) {
592     switch (type) {
593     case LT_KERNEL:
594        return LT_KERNEL_EFI;
595     case LT_INITRD:
596        return LT_INITRD_EFI;
597     default:
598        return type;
599     }
600        }
601        return type;
602    }
603    
604    static struct keywordTypes * getKeywordByType(enum lineType_e type,
605          struct configFileInfo * cfi) {
606        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
607     if (kw->type == type)
608        return kw;
609        }
610        return NULL;
611    }
612    
613    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
614        struct keywordTypes *kt = getKeywordByType(type, cfi);
615        if (kt)
616     return kt->key;
617        return "unknown";
618    }
619    
620    static char * getpathbyspec(char *device) {
621        if (!blkid)
622            blkid_get_cache(&blkid, NULL);
623    
624        return blkid_get_devname(blkid, device, NULL);
625    }
626    
627    static char * getuuidbydev(char *device) {
628        if (!blkid)
629     blkid_get_cache(&blkid, NULL);
630    
631        return blkid_get_tag_value(blkid, "UUID", device);
632    }
633    
634    static enum lineType_e getTypeByKeyword(char * keyword,
635     struct configFileInfo * cfi) {
636        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
637     if (cfi->caseInsensitive) {
638        if (!strcasecmp(keyword, kw->key))
639                    return kw->type;
640     } else {
641        if (!strcmp(keyword, kw->key))
642            return kw->type;
643     }
644        }
645        return LT_UNKNOWN;
646    }
647    
648    static struct singleLine * getLineByType(enum lineType_e type,
649     struct singleLine * line) {
650        dbgPrintf("getLineByType(%d): ", type);
651        for (; line; line = line->next) {
652     dbgPrintf("%d:%s ", line->type,
653      line->numElements ? line->elements[0].item : "(empty)");
654     if (line->type & type) break;
655        }
656        dbgPrintf(line ? "\n" : " (failed)\n");
657        return line;
658    }
659    
660  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
661      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
662          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
663          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
664              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 670  static int isBracketedTitle(struct singl
670      return 0;      return 0;
671  }  }
672    
673  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
674                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
675      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
676   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;  
677  }  }
678    
679  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 724  static void lineInit(struct singleLine *
724      line->next = NULL;      line->next = NULL;
725  }  }
726    
727  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
728      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
729    
730        newLine->indent = strdup(line->indent);
731        newLine->next = NULL;
732        newLine->type = line->type;
733        newLine->numElements = line->numElements;
734        newLine->elements = malloc(sizeof(*newLine->elements) *
735           newLine->numElements);
736    
737        for (int i = 0; i < newLine->numElements; i++) {
738     newLine->elements[i].indent = strdup(line->elements[i].indent);
739     newLine->elements[i].item = strdup(line->elements[i].item);
740        }
741    
742        return newLine;
743    }
744    
745    static void lineFree(struct singleLine * line) {
746      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
747    
748      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
749   free(line->elements[i].item);   free(line->elements[i].item);
750   free(line->elements[i].indent);   free(line->elements[i].indent);
751      }      }
# Line 405  static void lineFree(struct singleLine * Line 756  static void lineFree(struct singleLine *
756    
757  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
758       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
759      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
760    
761      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
762     /* Need to handle this, because we strip the quotes from
763     * menuentry when read it. */
764     if (line->type == LT_MENUENTRY && i == 1) {
765        if(!isquote(*line->elements[i].item))
766     fprintf(out, "\'%s\'", line->elements[i].item);
767        else
768     fprintf(out, "%s", line->elements[i].item);
769        fprintf(out, "%s", line->elements[i].indent);
770    
771        continue;
772     }
773    
774   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
775      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
776    
777   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
778   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
779        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
780      }      }
781    
782      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 795  static int getNextLine(char ** bufPtr, s
795      char * chptr;      char * chptr;
796      int elementsAlloced = 0;      int elementsAlloced = 0;
797      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
798      int first = 1;      int first = 1;
     int i;  
799    
800      lineFree(line);      lineFree(line);
801    
# Line 489  static int getNextLine(char ** bufPtr, s Line 849  static int getNextLine(char ** bufPtr, s
849      if (!line->numElements)      if (!line->numElements)
850   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
851      else {      else {
852   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
853      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;  
               
854              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
855               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
856              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 864  static int getNextLine(char ** bufPtr, s
864      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
865   char * fullLine;   char * fullLine;
866   int len;   int len;
  int i;  
867    
868   len = strlen(line->indent);   len = strlen(line->indent);
869   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
870      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
871     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
872    
# Line 522  static int getNextLine(char ** bufPtr, s Line 875  static int getNextLine(char ** bufPtr, s
875   free(line->indent);   free(line->indent);
876   line->indent = fullLine;   line->indent = fullLine;
877    
878   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
879      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
880      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
881      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 885  static int getNextLine(char ** bufPtr, s
885   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
886   line->numElements = 0;   line->numElements = 0;
887      }      }
888     } else {
889     struct keywordTypes *kw;
890    
891     kw = getKeywordByType(line->type, cfi);
892    
893     /* space isn't the only separator, we need to split
894     * elements up more
895     */
896     if (!isspace(kw->separatorChar)) {
897        char indent[2] = "";
898        indent[0] = kw->separatorChar;
899        for (int i = 1; i < line->numElements; i++) {
900     char *p;
901     int numNewElements;
902    
903     numNewElements = 0;
904     p = line->elements[i].item;
905     while (*p != '\0') {
906     if (*p == kw->separatorChar)
907     numNewElements++;
908     p++;
909     }
910     if (line->numElements + numNewElements >= elementsAlloced) {
911     elementsAlloced += numNewElements + 5;
912     line->elements = realloc(line->elements,
913        sizeof(*line->elements) * elementsAlloced);
914     }
915    
916     for (int j = line->numElements; j > i; j--) {
917     line->elements[j + numNewElements] = line->elements[j];
918     }
919     line->numElements += numNewElements;
920    
921     p = line->elements[i].item;
922     while (*p != '\0') {
923    
924     while (*p != kw->separatorChar && *p != '\0') p++;
925     if (*p == '\0') {
926     break;
927     }
928    
929     line->elements[i + 1].indent = line->elements[i].indent;
930     line->elements[i].indent = strdup(indent);
931     *p++ = '\0';
932     i++;
933     line->elements[i].item = strdup(p);
934     }
935        }
936     }
937   }   }
938      }      }
939    
# Line 549  static struct grubConfig * readConfig(co Line 951  static struct grubConfig * readConfig(co
951      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
952      char * end;      char * end;
953      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
954      int i, len;      int len;
955      char * buf;      char * buf;
956    
957      if (!strcmp(inName, "-")) {      if (!strcmp(inName, "-")) {
# Line 595  static struct grubConfig * readConfig(co Line 997  static struct grubConfig * readConfig(co
997      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
998   }   }
999    
1000   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1001      sawEntry = 1;      sawEntry = 1;
1002      if (!entry) {      if (!entry) {
1003   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1013  static struct grubConfig * readConfig(co
1013      entry->next = NULL;      entry->next = NULL;
1014   }   }
1015    
1016   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1017        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1018        dbgPrintf("%s", line->indent);
1019        for (int i = 0; i < line->numElements; i++)
1020     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1021        dbgPrintf("\n");
1022        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1023        if (kwType && line->numElements == 3 &&
1024        !strcmp(line->elements[1].item, kwType->key)) {
1025     dbgPrintf("Line sets default config\n");
1026     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1027     defaultLine = line;
1028        }
1029     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1030      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1031      defaultLine = line;      defaultLine = line;
1032    
1033            } else if (iskernel(line->type)) {
1034        /* if by some freak chance this is multiboot and the "module"
1035         * lines came earlier in the template, make sure to use LT_HYPER
1036         * instead of LT_KERNEL now
1037         */
1038        if (entry->multiboot)
1039     line->type = LT_HYPER;
1040    
1041          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1042        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1043         * instead, now that we know this is a multiboot entry.
1044         * This only applies to grub, but that's the only place we
1045         * should find LT_MBMODULE lines anyway.
1046         */
1047        for (struct singleLine *l = entry->lines; l; l = l->next) {
1048     if (l->type == LT_HYPER)
1049        break;
1050     else if (iskernel(l->type)) {
1051        l->type = LT_HYPER;
1052        break;
1053     }
1054        }
1055              entry->multiboot = 1;              entry->multiboot = 1;
1056    
1057     } else if (line->type == LT_HYPER) {
1058        entry->multiboot = 1;
1059    
1060   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1061      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1062      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1063    
1064   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1065      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1066      len = 0;      len = 0;
1067      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1068   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1069   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1070      }      }
1071      buf = malloc(len + 1);      buf = malloc(len + 1);
1072      *buf = '\0';      *buf = '\0';
1073    
1074      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1075   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1076   free(line->elements[i].item);   free(line->elements[i].item);
1077    
# Line 643  static struct grubConfig * readConfig(co Line 1085  static struct grubConfig * readConfig(co
1085      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1086      line->elements[1].item = buf;      line->elements[1].item = buf;
1087      line->numElements = 2;      line->numElements = 2;
1088     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1089        /* let --remove-kernel="TITLE=what" work */
1090        len = 0;
1091        char *extras;
1092        char *title;
1093    
1094        for (int i = 1; i < line->numElements; i++) {
1095     len += strlen(line->elements[i].item);
1096     len += strlen(line->elements[i].indent);
1097        }
1098        buf = malloc(len + 1);
1099        *buf = '\0';
1100    
1101        /* allocate mem for extra flags. */
1102        extras = malloc(len + 1);
1103        *extras = '\0';
1104    
1105        /* get title. */
1106        for (int i = 0; i < line->numElements; i++) {
1107     if (!strcmp(line->elements[i].item, "menuentry"))
1108        continue;
1109     if (isquote(*line->elements[i].item))
1110        title = line->elements[i].item + 1;
1111     else
1112        title = line->elements[i].item;
1113    
1114     len = strlen(title);
1115            if (isquote(title[len-1])) {
1116        strncat(buf, title,len-1);
1117        break;
1118     } else {
1119        strcat(buf, title);
1120        strcat(buf, line->elements[i].indent);
1121     }
1122        }
1123    
1124        /* get extras */
1125        int count = 0;
1126        for (int i = 0; i < line->numElements; i++) {
1127     if (count >= 2) {
1128        strcat(extras, line->elements[i].item);
1129        strcat(extras, line->elements[i].indent);
1130     }
1131    
1132     if (!strcmp(line->elements[i].item, "menuentry"))
1133        continue;
1134    
1135     /* count ' or ", there should be two in menuentry line. */
1136     if (isquote(*line->elements[i].item))
1137        count++;
1138    
1139     len = strlen(line->elements[i].item);
1140    
1141     if (isquote(line->elements[i].item[len -1]))
1142        count++;
1143    
1144     /* ok, we get the final ' or ", others are extras. */
1145                }
1146        line->elements[1].indent =
1147     line->elements[line->numElements - 2].indent;
1148        line->elements[1].item = buf;
1149        line->elements[2].indent =
1150     line->elements[line->numElements - 2].indent;
1151        line->elements[2].item = extras;
1152        line->numElements = 3;
1153   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1154      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1155         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 1158  static struct grubConfig * readConfig(co
1158      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1159   int last, len;   int last, len;
1160    
1161   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1162      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1163     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1164    
1165   last = line->numElements - 1;   last = line->numElements - 1;
1166   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1167   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1168      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1169      }      }
   
1170   }   }
1171    
1172   /* 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 1186  static struct grubConfig * readConfig(co
1186   movedLine = 1;   movedLine = 1;
1187   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1188   }   }
1189    
1190   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1191     which was moved, drop it. */     which was moved, drop it. */
1192   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 1202  static struct grubConfig * readConfig(co
1202   entry->lines = line;   entry->lines = line;
1203      else      else
1204   last->next = line;   last->next = line;
1205        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1206    
1207        /* we could have seen this outside of an entry... if so, we
1208         * ignore it like any other line we don't grok */
1209        if (line->type == LT_ENTRY_END && sawEntry)
1210     sawEntry = 0;
1211   } else {   } else {
1212      if (!cfg->theLines)      if (!cfg->theLines)
1213   cfg->theLines = line;   cfg->theLines = line;
1214      else {      else
1215   last->next = line;   last->next = line;
1216      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1217   }   }
1218    
1219   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1221  static struct grubConfig * readConfig(co
1221    
1222      free(incoming);      free(incoming);
1223    
1224        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1225      if (defaultLine) {      if (defaultLine) {
1226   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1227        cfi->defaultSupportSaved &&
1228        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1229        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1230     } else if (cfi->defaultIsVariable) {
1231        char *value = defaultLine->elements[2].item;
1232        while (*value && (*value == '"' || *value == '\'' ||
1233        *value == ' ' || *value == '\t'))
1234     value++;
1235        cfg->defaultImage = strtol(value, &end, 10);
1236        while (*end && (*end == '"' || *end == '\'' ||
1237        *end == ' ' || *end == '\t'))
1238     end++;
1239        if (*end) cfg->defaultImage = -1;
1240     } else if (cfi->defaultSupportSaved &&
1241   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1242      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1243   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1244      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1245      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1246   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1247      i = 0;      int i = 0;
1248      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1249   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1250      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1258  static struct grubConfig * readConfig(co
1258                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1259                  }                  }
1260   i++;   i++;
1261     entry = NULL;
1262      }      }
1263    
1264      if (entry) cfg->defaultImage = i;      if (entry){
1265            cfg->defaultImage = i;
1266        }else{
1267            cfg->defaultImage = -1;
1268        }
1269   }   }
1270        } else {
1271            cfg->defaultImage = 0;
1272      }      }
1273    
1274      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1284  static void writeDefault(FILE * out, cha
1284    
1285      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1286   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1287        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1288     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1289      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1290   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1291      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1292      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1293     cfg->defaultImage);
1294        } else {
1295     fprintf(out, "%sdefault%s%d\n", indent, separator,
1296     cfg->defaultImage);
1297        }
1298   } else {   } else {
1299      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1300    
# Line 769  static void writeDefault(FILE * out, cha Line 1311  static void writeDefault(FILE * out, cha
1311    
1312      if (!entry) return;      if (!entry) return;
1313    
1314      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1315    
1316      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1317   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1345  static int writeConfig(struct grubConfig
1345      int rc;      int rc;
1346    
1347      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1348         directory to / */         directory to the dir of the symlink */
1349      rc = chdir("/");      char *dir = strdupa(outName);
1350        rc = chdir(dirname(dir));
1351      do {      do {
1352   buf = alloca(len + 1);   buf = alloca(len + 1);
1353   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1354   if (rc == len) len += 256;   if (rc == len) len += 256;
1355      } while (rc == len);      } while (rc == len);
1356            
# Line 843  static int writeConfig(struct grubConfig Line 1385  static int writeConfig(struct grubConfig
1385      }      }
1386    
1387      line = cfg->theLines;      line = cfg->theLines;
1388        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1389      while (line) {      while (line) {
1390   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1391     line->numElements == 3 &&
1392     !strcmp(line->elements[1].item, defaultKw->key)) {
1393        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1394        needs &= ~MAIN_DEFAULT;
1395     } else if (line->type == LT_DEFAULT) {
1396      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1397      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1398   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1460  static int numEntries(struct grubConfig
1460      return i;      return i;
1461  }  }
1462    
1463    static char *findDiskForRoot()
1464    {
1465        int fd;
1466        char buf[65536];
1467        char *devname;
1468        char *chptr;
1469        int rc;
1470    
1471        if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1472            fprintf(stderr, "grubby: failed to open %s: %s\n",
1473                    _PATH_MOUNTED, strerror(errno));
1474            return NULL;
1475        }
1476    
1477        rc = read(fd, buf, sizeof(buf) - 1);
1478        if (rc <= 0) {
1479            fprintf(stderr, "grubby: failed to read %s: %s\n",
1480                    _PATH_MOUNTED, strerror(errno));
1481            close(fd);
1482            return NULL;
1483        }
1484        close(fd);
1485        buf[rc] = '\0';
1486        chptr = buf;
1487    
1488        char *foundanswer = NULL;
1489    
1490        while (chptr && chptr != buf+rc) {
1491            devname = chptr;
1492    
1493            /*
1494             * The first column of a mtab entry is the device, but if the entry is a
1495             * special device it won't start with /, so move on to the next line.
1496             */
1497            if (*devname != '/') {
1498                chptr = strchr(chptr, '\n');
1499                if (chptr)
1500                    chptr++;
1501                continue;
1502            }
1503    
1504            /* Seek to the next space */
1505            chptr = strchr(chptr, ' ');
1506            if (!chptr) {
1507                fprintf(stderr, "grubby: error parsing %s: %s\n",
1508                        _PATH_MOUNTED, strerror(errno));
1509                return NULL;
1510            }
1511    
1512            /*
1513             * The second column of a mtab entry is the mount point, we are looking
1514             * for '/' obviously.
1515             */
1516            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1517                /* remember the last / entry in mtab */
1518               foundanswer = devname;
1519            }
1520    
1521            /* Next line */
1522            chptr = strchr(chptr, '\n');
1523            if (chptr)
1524                chptr++;
1525        }
1526    
1527        /* Return the last / entry found */
1528        if (foundanswer) {
1529            chptr = strchr(foundanswer, ' ');
1530            *chptr = '\0';
1531            return strdup(foundanswer);
1532        }
1533    
1534        return NULL;
1535    }
1536    
1537    void printEntry(struct singleEntry * entry) {
1538        int i;
1539        struct singleLine * line;
1540    
1541        for (line = entry->lines; line; line = line->next) {
1542     fprintf(stderr, "DBG: %s", line->indent);
1543     for (i = 0; i < line->numElements; i++) {
1544        /* Need to handle this, because we strip the quotes from
1545         * menuentry when read it. */
1546        if (line->type == LT_MENUENTRY && i == 1) {
1547     if(!isquote(*line->elements[i].item))
1548        fprintf(stderr, "\'%s\'", line->elements[i].item);
1549     else
1550        fprintf(stderr, "%s", line->elements[i].item);
1551     fprintf(stderr, "%s", line->elements[i].indent);
1552    
1553     continue;
1554        }
1555        
1556        fprintf(stderr, "%s%s",
1557        line->elements[i].item, line->elements[i].indent);
1558     }
1559     fprintf(stderr, "\n");
1560        }
1561    }
1562    
1563    void notSuitablePrintf(struct singleEntry * entry, const char *fmt, ...)
1564    {
1565        va_list argp;
1566    
1567        if (!debug)
1568     return;
1569    
1570        va_start(argp, fmt);
1571        fprintf(stderr, "DBG: Image entry failed: ");
1572        vfprintf(stderr, fmt, argp);
1573        printEntry(entry);
1574        va_end(argp);
1575    }
1576    
1577    #define beginswith(s, c) ((s) && (s)[0] == (c))
1578    
1579    static int endswith(const char *s, char c)
1580    {
1581     int slen;
1582    
1583     if (!s || !s[0])
1584     return 0;
1585     slen = strlen(s) - 1;
1586    
1587     return s[slen] == c;
1588    }
1589    
1590  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1591    int skipRemoved, int flags) {    int skipRemoved, int flags) {
1592      struct singleLine * line;      struct singleLine * line;
1593      char * fullName;      char * fullName;
1594      int i;      int i;
     struct stat sb, sb2;  
1595      char * dev;      char * dev;
     char * end;  
1596      char * rootspec;      char * rootspec;
1597        char * rootdev;
1598    
1599      line = entry->lines;      if (skipRemoved && entry->skip) {
1600      while (line && line->type != LT_KERNEL) line = line->next;   notSuitablePrintf(entry, "marked to skip\n");
1601         return 0;
1602      if (!line) return 0;      }
1603      if (skipRemoved && entry->skip) return 0;  
1604      if (line->numElements < 2) return 0;      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1605        if (!line) {
1606     notSuitablePrintf(entry, "no line found\n");
1607     return 0;
1608        }
1609        if (line->numElements < 2) {
1610     notSuitablePrintf(entry, "line has only %d elements\n",
1611        line->numElements);
1612     return 0;
1613        }
1614    
1615      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;
1616    
1617      fullName = alloca(strlen(bootPrefix) +      fullName = alloca(strlen(bootPrefix) +
1618        strlen(line->elements[1].item) + 1);        strlen(line->elements[1].item) + 1);
1619      rootspec = getRootSpecifier(line->elements[1].item);      rootspec = getRootSpecifier(line->elements[1].item);
1620      sprintf(fullName, "%s%s", bootPrefix,      int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1621              line->elements[1].item + ((rootspec != NULL) ?      int hasslash = endswith(bootPrefix, '/') ||
1622                                        strlen(rootspec) : 0));       beginswith(line->elements[1].item + rootspec_offset, '/');
1623      if (access(fullName, R_OK)) return 0;      sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1624                line->elements[1].item + rootspec_offset);
1625        if (access(fullName, R_OK)) {
1626     notSuitablePrintf(entry, "access to %s failed\n", fullName);
1627     return 0;
1628        }
1629      for (i = 2; i < line->numElements; i++)      for (i = 2; i < line->numElements; i++)
1630   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1631      if (i < line->numElements) {      if (i < line->numElements) {
1632   dev = line->elements[i].item + 5;   dev = line->elements[i].item + 5;
1633      } else {      } else {
1634   /* look for a lilo style LT_ROOT line */   /* look for a lilo style LT_ROOT line */
1635   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
1636    
1637   if (line && line->numElements >= 2) {   if (line && line->numElements >= 2) {
1638      dev = line->elements[1].item;      dev = line->elements[1].item;
1639   } else {   } else {
1640              int type;      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1641      /* 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.
1642      line = entry->lines;       */
1643        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
             type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);  
   
     while (line && line->type != type) line = line->next;  
1644    
1645              /* failed to find one */              /* failed to find one */
1646              if (!line) return 0;              if (!line) {
1647     notSuitablePrintf(entry, "no line found\n");
1648     return 0;
1649                }
1650    
1651      for (i = 1; i < line->numElements; i++)      for (i = 1; i < line->numElements; i++)
1652          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1653      if (i < line->numElements)      if (i < line->numElements)
1654          dev = line->elements[i].item + 5;          dev = line->elements[i].item + 5;
1655      else {      else {
1656     notSuitablePrintf(entry, "no root= entry found\n");
1657   /* it failed too...  can't find root= */   /* it failed too...  can't find root= */
1658          return 0;          return 0;
1659              }              }
1660   }   }
1661      }      }
1662    
1663      if (!strncmp(dev, "LABEL=", 6)) {      dev = getpathbyspec(dev);
1664   dev += 6;      if (!getpathbyspec(dev)) {
1665            notSuitablePrintf(entry, "can't find blkid entry for %s\n", dev);
1666   /* check which device has this label */          return 0;
1667   dev = get_spec_by_volume_label(dev, &i, &i);      } else
1668   if (!dev) return 0;   dev = getpathbyspec(dev);
1669    
1670        rootdev = findDiskForRoot();
1671        if (!rootdev) {
1672            notSuitablePrintf(entry, "can't find root device\n");
1673     return 0;
1674      }      }
1675    
1676      if (*dev == '/') {      if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1677   if (stat(dev, &sb))          notSuitablePrintf(entry, "uuid missing: rootdev %s, dev %s\n",
1678      return 0;   getuuidbydev(rootdev), getuuidbydev(dev));
1679      } else {          free(rootdev);
1680   sb.st_rdev = strtol(dev, &end, 16);          return 0;
1681   if (*end) return 0;      }
1682    
1683        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1684            notSuitablePrintf(entry, "uuid mismatch: rootdev %s, dev %s\n",
1685     getuuidbydev(rootdev), getuuidbydev(dev));
1686     free(rootdev);
1687            return 0;
1688      }      }
     stat("/", &sb2);  
1689    
1690      if (sb.st_rdev != sb2.st_dev) return 0;      free(rootdev);
1691    
1692      return 1;      return 1;
1693  }  }
# Line 1034  struct singleEntry * findEntryByPath(str Line 1731  struct singleEntry * findEntryByPath(str
1731   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1732   if (!entry) return NULL;   if (!entry) return NULL;
1733    
1734   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1735   if (!line) return NULL;   if (!line) return NULL;
1736    
1737   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1769  struct singleEntry * findEntryByPath(str
1769    
1770   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1771      prefix = "";      prefix = "";
1772      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1773      kernel += 6;      kernel += 6;
1774   }   }
1775    
1776   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1777      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1778    
1779        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1780    
1781      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1782                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1783          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
1784                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1785                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1786                      break;   else if (checkType & LT_KERNEL)
1787              }      ct = checkType | LT_KERNEL_EFI;
1788                 line = getLineByType(ct, line);
1789              /* have to check multiboot lines too */   if (!line)
1790              if (entry->multiboot) {      break;  /* not found in this entry */
1791                  while (line && line->type != LT_MBMODULE) line = line->next;  
1792                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
1793                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
1794                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
1795                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
1796                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
1797                          break;   kernel + strlen(prefix)))
1798                  }   break;
1799              }   }
1800     if(line->type == LT_MENUENTRY &&
1801     !strcmp(line->elements[1].item, kernel))
1802        break;
1803        }
1804    
1805      i++;      /* make sure this entry has a kernel identifier; this skips
1806         * non-Linux boot entries (could find netbsd etc, though, which is
1807         * unfortunate)
1808         */
1809        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1810     break; /* found 'im! */
1811   }   }
1812    
1813   if (index) *index = i;   if (index) *index = i;
1814      }      }
1815    
     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);  
     }  
   
1816      return entry;      return entry;
1817  }  }
1818    
# Line 1200  void markRemovedImage(struct grubConfig Line 1891  void markRemovedImage(struct grubConfig
1891        const char * prefix) {        const char * prefix) {
1892      struct singleEntry * entry;      struct singleEntry * entry;
1893    
1894      if (!image) return;      if (!image)
1895     return;
1896    
1897        /* check and see if we're removing the default image */
1898        if (isdigit(*image)) {
1899     entry = findEntryByPath(cfg, image, prefix, NULL);
1900     if(entry)
1901        entry->skip = 1;
1902     return;
1903        }
1904    
1905      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1906   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1908  void markRemovedImage(struct grubConfig
1908    
1909  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1910       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1911       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1912      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1913      int i, j;      int i, j;
1914    
1915      if (newIsDefault) {      if (newIsDefault) {
1916   config->defaultImage = 0;   config->defaultImage = 0;
1917   return;   return;
1918        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1919     if (findEntryByIndex(config, index))
1920        config->defaultImage = index;
1921     else
1922        config->defaultImage = -1;
1923     return;
1924      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1925   i = 0;   i = 0;
1926   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1933  void setDefaultImage(struct grubConfig *
1933    
1934      /* 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
1935         changes */         changes */
1936      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1937     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1938        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1939        return;        return;
1940    
# Line 1286  void displayEntry(struct singleEntry * e Line 1993  void displayEntry(struct singleEntry * e
1993      char * root = NULL;      char * root = NULL;
1994      int i;      int i;
1995    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
1996      printf("index=%d\n", index);      printf("index=%d\n", index);
1997    
1998      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1999        if (!line) {
2000            printf("non linux entry\n");
2001            return;
2002        }
2003    
2004        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2005     printf("kernel=%s\n", line->elements[1].item);
2006        else
2007     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2008    
2009      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2010   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2021  void displayEntry(struct singleEntry * e
2021   }   }
2022   printf("\"\n");   printf("\"\n");
2023      } else {      } else {
2024   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2025   if (line) {   if (line) {
2026      char * s;      char * s;
2027    
# Line 1334  void displayEntry(struct singleEntry * e Line 2045  void displayEntry(struct singleEntry * e
2045      }      }
2046    
2047      if (!root) {      if (!root) {
2048   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2049   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2050      root=line->elements[1].item;      root=line->elements[1].item;
2051      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2060  void displayEntry(struct singleEntry * e
2060   printf("root=%s\n", s);   printf("root=%s\n", s);
2061      }      }
2062    
2063      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2064    
2065      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2066   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2067        printf("initrd=");
2068     else
2069        printf("initrd=%s", prefix);
2070    
2071   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2072      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2073   printf("\n");   printf("\n");
2074      }      }
2075    
2076        line = getLineByType(LT_TITLE, entry->lines);
2077        if (line) {
2078     printf("title=%s\n", line->elements[1].item);
2079        } else {
2080     char * title;
2081     line = getLineByType(LT_MENUENTRY, entry->lines);
2082     title = grub2ExtractTitle(line);
2083     if (title)
2084        printf("title=%s\n", title);
2085        }
2086    }
2087    
2088    int isSuseSystem(void) {
2089        const char * path;
2090        const static char default_path[] = "/etc/SuSE-release";
2091    
2092        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2093     path = default_path;
2094    
2095        if (!access(path, R_OK))
2096     return 1;
2097        return 0;
2098    }
2099    
2100    int isSuseGrubConf(const char * path) {
2101        FILE * grubConf;
2102        char * line = NULL;
2103        size_t len = 0, res = 0;
2104    
2105        grubConf = fopen(path, "r");
2106        if (!grubConf) {
2107            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2108     return 0;
2109        }
2110    
2111        while ((res = getline(&line, &len, grubConf)) != -1) {
2112     if (!strncmp(line, "setup", 5)) {
2113        fclose(grubConf);
2114        free(line);
2115        return 1;
2116     }
2117        }
2118    
2119        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2120          path);
2121    
2122        fclose(grubConf);
2123        free(line);
2124        return 0;
2125    }
2126    
2127    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2128        FILE * grubConf;
2129        char * line = NULL;
2130        size_t res = 0, len = 0;
2131    
2132        if (!path) return 1;
2133        if (!lbaPtr) return 1;
2134    
2135        grubConf = fopen(path, "r");
2136        if (!grubConf) return 1;
2137    
2138        while ((res = getline(&line, &len, grubConf)) != -1) {
2139     if (line[res - 1] == '\n')
2140        line[res - 1] = '\0';
2141     else if (len > res)
2142        line[res] = '\0';
2143     else {
2144        line = realloc(line, res + 1);
2145        line[res] = '\0';
2146     }
2147    
2148     if (!strncmp(line, "setup", 5)) {
2149        if (strstr(line, "--force-lba")) {
2150            *lbaPtr = 1;
2151        } else {
2152            *lbaPtr = 0;
2153        }
2154        dbgPrintf("lba: %i\n", *lbaPtr);
2155        break;
2156     }
2157        }
2158    
2159        free(line);
2160        fclose(grubConf);
2161        return 0;
2162    }
2163    
2164    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2165        FILE * grubConf;
2166        char * line = NULL;
2167        size_t res = 0, len = 0;
2168        char * lastParamPtr = NULL;
2169        char * secLastParamPtr = NULL;
2170        char installDeviceNumber = '\0';
2171        char * bounds = NULL;
2172    
2173        if (!path) return 1;
2174        if (!devicePtr) return 1;
2175    
2176        grubConf = fopen(path, "r");
2177        if (!grubConf) return 1;
2178    
2179        while ((res = getline(&line, &len, grubConf)) != -1) {
2180     if (strncmp(line, "setup", 5))
2181        continue;
2182    
2183     if (line[res - 1] == '\n')
2184        line[res - 1] = '\0';
2185     else if (len > res)
2186        line[res] = '\0';
2187     else {
2188        line = realloc(line, res + 1);
2189        line[res] = '\0';
2190     }
2191    
2192     lastParamPtr = bounds = line + res;
2193    
2194     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2195     while (!isspace(*lastParamPtr))
2196        lastParamPtr--;
2197     lastParamPtr++;
2198    
2199     secLastParamPtr = lastParamPtr - 2;
2200     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2201    
2202     if (lastParamPtr + 3 > bounds) {
2203        dbgPrintf("lastParamPtr going over boundary");
2204        fclose(grubConf);
2205        free(line);
2206        return 1;
2207     }
2208     if (!strncmp(lastParamPtr, "(hd", 3))
2209        lastParamPtr += 3;
2210     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2211    
2212     /*
2213     * Second last parameter will decide wether last parameter is
2214     * an IMAGE_DEVICE or INSTALL_DEVICE
2215     */
2216     while (!isspace(*secLastParamPtr))
2217        secLastParamPtr--;
2218     secLastParamPtr++;
2219    
2220     if (secLastParamPtr + 3 > bounds) {
2221        dbgPrintf("secLastParamPtr going over boundary");
2222        fclose(grubConf);
2223        free(line);
2224        return 1;
2225     }
2226     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2227     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2228        secLastParamPtr += 3;
2229        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2230        installDeviceNumber = *secLastParamPtr;
2231     } else {
2232        installDeviceNumber = *lastParamPtr;
2233     }
2234    
2235     *devicePtr = malloc(6);
2236     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2237     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2238     fclose(grubConf);
2239     free(line);
2240     return 0;
2241        }
2242    
2243        free(line);
2244        fclose(grubConf);
2245        return 1;
2246    }
2247    
2248    int grubGetBootFromDeviceMap(const char * device,
2249         char ** bootPtr) {
2250        FILE * deviceMap;
2251        char * line = NULL;
2252        size_t res = 0, len = 0;
2253        char * devicePtr;
2254        char * bounds = NULL;
2255        const char * path;
2256        const static char default_path[] = "/boot/grub/device.map";
2257    
2258        if (!device) return 1;
2259        if (!bootPtr) return 1;
2260    
2261        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2262     path = default_path;
2263    
2264        dbgPrintf("opening grub device.map file from: %s\n", path);
2265        deviceMap = fopen(path, "r");
2266        if (!deviceMap)
2267     return 1;
2268    
2269        while ((res = getline(&line, &len, deviceMap)) != -1) {
2270            if (!strncmp(line, "#", 1))
2271        continue;
2272    
2273     if (line[res - 1] == '\n')
2274        line[res - 1] = '\0';
2275     else if (len > res)
2276        line[res] = '\0';
2277     else {
2278        line = realloc(line, res + 1);
2279        line[res] = '\0';
2280     }
2281    
2282     devicePtr = line;
2283     bounds = line + res;
2284    
2285     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2286        devicePtr++;
2287     dbgPrintf("device: %s\n", devicePtr);
2288    
2289     if (!strncmp(devicePtr, device, strlen(device))) {
2290        devicePtr += strlen(device);
2291        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2292            devicePtr++;
2293    
2294        *bootPtr = strdup(devicePtr);
2295        break;
2296     }
2297        }
2298    
2299        free(line);
2300        fclose(deviceMap);
2301        return 0;
2302    }
2303    
2304    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2305        char * grubDevice;
2306    
2307        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2308     dbgPrintf("error looking for grub installation device\n");
2309        else
2310     dbgPrintf("grubby installation device: %s\n", grubDevice);
2311    
2312        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2313     dbgPrintf("error looking for grub boot device\n");
2314        else
2315     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2316    
2317        free(grubDevice);
2318        return 0;
2319    }
2320    
2321    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2322        /*
2323         * This SuSE grub configuration file at this location is not your average
2324         * grub configuration file, but instead the grub commands used to setup
2325         * grub on that system.
2326         */
2327        const char * path;
2328        const static char default_path[] = "/etc/grub.conf";
2329    
2330        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2331     path = default_path;
2332    
2333        if (!isSuseGrubConf(path)) return 1;
2334    
2335        if (lbaPtr) {
2336            *lbaPtr = 0;
2337            if (suseGrubConfGetLba(path, lbaPtr))
2338                return 1;
2339        }
2340    
2341        if (bootPtr) {
2342            *bootPtr = NULL;
2343            suseGrubConfGetBoot(path, bootPtr);
2344        }
2345    
2346        return 0;
2347  }  }
2348    
2349  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2353  int parseSysconfigGrub(int * lbaPtr, cha
2353      char * start;      char * start;
2354      char * param;      char * param;
2355    
2356      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2357      if (!in) return 1;      if (!in) return 1;
2358    
2359      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2394  int parseSysconfigGrub(int * lbaPtr, cha
2394  }  }
2395    
2396  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2397      char * boot;      char * boot = NULL;
2398      int lba;      int lba;
2399    
2400      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2401   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2402   if (boot) printf("boot=%s\n", boot);      free(boot);
2403        return;
2404     }
2405        } else {
2406            if (parseSysconfigGrub(&lba, &boot)) {
2407        free(boot);
2408        return;
2409     }
2410        }
2411    
2412        if (lba) printf("lba\n");
2413        if (boot) {
2414     printf("boot=%s\n", boot);
2415     free(boot);
2416      }      }
2417  }  }
2418    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2428  int displayInfo(struct grubConfig * conf
2428   return 1;   return 1;
2429      }      }
2430    
2431      /* 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
2432         be a better way */         be a better way */
2433      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2434   dumpSysconfigGrub();   dumpSysconfigGrub();
2435      } else {      } else {
2436   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2437   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2438      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2439   }   }
2440    
2441   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2442   if (line) printf("lba\n");   if (line) printf("lba\n");
2443      }      }
2444    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2453  int displayInfo(struct grubConfig * conf
2453      return 0;      return 0;
2454  }  }
2455    
2456    struct singleLine * addLineTmpl(struct singleEntry * entry,
2457     struct singleLine * tmplLine,
2458     struct singleLine * prevLine,
2459     const char * val,
2460     struct configFileInfo * cfi)
2461    {
2462        struct singleLine * newLine = lineDup(tmplLine);
2463    
2464        if (isEfi && cfi == &grub2ConfigType) {
2465     enum lineType_e old = newLine->type;
2466     newLine->type = preferredLineType(newLine->type, cfi);
2467     if (old != newLine->type)
2468        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2469        }
2470    
2471        if (val) {
2472     /* override the inherited value with our own.
2473     * This is a little weak because it only applies to elements[1]
2474     */
2475     if (newLine->numElements > 1)
2476        removeElement(newLine, 1);
2477     insertElement(newLine, val, 1, cfi);
2478    
2479     /* but try to keep the rootspec from the template... sigh */
2480     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2481        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2482        if (rootspec != NULL) {
2483     free(newLine->elements[1].item);
2484     newLine->elements[1].item =
2485        sdupprintf("%s%s", rootspec, val);
2486        }
2487     }
2488        }
2489    
2490        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2491          newLine->elements[0].item : "");
2492    
2493        if (!entry->lines) {
2494     /* first one on the list */
2495     entry->lines = newLine;
2496        } else if (prevLine) {
2497     /* add after prevLine */
2498     newLine->next = prevLine->next;
2499     prevLine->next = newLine;
2500        }
2501    
2502        return newLine;
2503    }
2504    
2505  /* val may be NULL */  /* val may be NULL */
2506  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2507       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2508       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2509       char * val) {       const char * val) {
2510      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2511      int i;      struct keywordTypes * kw;
2512        struct singleLine tmpl;
2513    
2514      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2515   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2516      if (type != LT_TITLE || !cfi->titleBracketed)       */
2517          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2518     /* we're doing a bracketed title (zipl) */
2519     tmpl.type = type;
2520     tmpl.numElements = 1;
2521     tmpl.elements = alloca(sizeof(*tmpl.elements));
2522     tmpl.elements[0].item = alloca(strlen(val)+3);
2523     sprintf(tmpl.elements[0].item, "[%s]", val);
2524     tmpl.elements[0].indent = "";
2525     val = NULL;
2526        } else if (type == LT_MENUENTRY) {
2527     char *lineend = "--class gnu-linux --class gnu --class os {";
2528     if (!val) {
2529        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2530        abort();
2531     }
2532     kw = getKeywordByType(type, cfi);
2533     if (!kw) {
2534        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2535        abort();
2536     }
2537     tmpl.indent = "";
2538     tmpl.type = type;
2539     tmpl.numElements = 3;
2540     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2541     tmpl.elements[0].item = kw->key;
2542     tmpl.elements[0].indent = alloca(2);
2543     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2544     tmpl.elements[1].item = (char *)val;
2545     tmpl.elements[1].indent = alloca(2);
2546     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2547     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2548     strcpy(tmpl.elements[2].item, lineend);
2549     tmpl.elements[2].indent = "";
2550        } else {
2551     kw = getKeywordByType(type, cfi);
2552     if (!kw) {
2553        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2554        abort();
2555     }
2556     tmpl.type = type;
2557     tmpl.numElements = val ? 2 : 1;
2558     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2559     tmpl.elements[0].item = kw->key;
2560     tmpl.elements[0].indent = alloca(2);
2561     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2562     if (val) {
2563        tmpl.elements[1].item = (char *)val;
2564        tmpl.elements[1].indent = "";
2565     }
2566        }
2567    
2568      /* 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
2569         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2570         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
2571         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2572         differently from the rest) */         differently from the rest) */
2573      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2574   line = entry->lines;   if (line->numElements) prev = line;
2575   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2576   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;  
2577      }      }
2578    
2579      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2580          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2581          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2582          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2583          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2584          line->elements[0].indent = malloc(2);   else
2585          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2586          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2587             if (menuEntry)
2588          if (val) {      tmpl.indent = "\t";
2589              line->elements[1].item = val;   else if (prev == entry->lines)
2590              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2591          }   else
2592      } 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("");  
2593      }      }
2594    
2595      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2596  }  }
2597    
2598  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2617  void removeLine(struct singleEntry * ent
2617      free(line);      free(line);
2618  }  }
2619    
2620    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2621    {
2622        struct singleLine newLine = {
2623     .indent = tmplLine->indent,
2624     .type = tmplLine->type,
2625     .next = tmplLine->next,
2626        };
2627        int firstQuotedItem = -1;
2628        int quoteLen = 0;
2629        int j;
2630        int element = 0;
2631        char *c;
2632    
2633        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2634        strcpy(c, tmplLine->elements[0].item);
2635        insertElement(&newLine, c, element++, cfi);
2636        free(c);
2637        c = NULL;
2638    
2639        for (j = 1; j < tmplLine->numElements; j++) {
2640     if (firstQuotedItem == -1) {
2641        quoteLen += strlen(tmplLine->elements[j].item);
2642        
2643        if (isquote(tmplLine->elements[j].item[0])) {
2644     firstQuotedItem = j;
2645            quoteLen += strlen(tmplLine->elements[j].indent);
2646        } else {
2647     c = malloc(quoteLen + 1);
2648     strcpy(c, tmplLine->elements[j].item);
2649     insertElement(&newLine, c, element++, cfi);
2650     free(c);
2651     quoteLen = 0;
2652        }
2653     } else {
2654        int itemlen = strlen(tmplLine->elements[j].item);
2655        quoteLen += itemlen;
2656        quoteLen += strlen(tmplLine->elements[j].indent);
2657        
2658        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2659     c = malloc(quoteLen + 1);
2660     c[0] = '\0';
2661     for (int i = firstQuotedItem; i < j+1; i++) {
2662        strcat(c, tmplLine->elements[i].item);
2663        strcat(c, tmplLine->elements[i].indent);
2664     }
2665     insertElement(&newLine, c, element++, cfi);
2666     free(c);
2667    
2668     firstQuotedItem = -1;
2669     quoteLen = 0;
2670        }
2671     }
2672        }
2673        while (tmplLine->numElements)
2674     removeElement(tmplLine, 0);
2675        if (tmplLine->elements)
2676     free(tmplLine->elements);
2677    
2678        tmplLine->numElements = newLine.numElements;
2679        tmplLine->elements = newLine.elements;
2680    }
2681    
2682    static void insertElement(struct singleLine * line,
2683      const char * item, int insertHere,
2684      struct configFileInfo * cfi)
2685    {
2686        struct keywordTypes * kw;
2687        char indent[2] = "";
2688    
2689        /* sanity check */
2690        if (insertHere > line->numElements) {
2691     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2692      insertHere, line->numElements);
2693     insertHere = line->numElements;
2694        }
2695    
2696        line->elements = realloc(line->elements, (line->numElements + 1) *
2697         sizeof(*line->elements));
2698        memmove(&line->elements[insertHere+1],
2699        &line->elements[insertHere],
2700        (line->numElements - insertHere) *
2701        sizeof(*line->elements));
2702        line->elements[insertHere].item = strdup(item);
2703    
2704        kw = getKeywordByType(line->type, cfi);
2705    
2706        if (line->numElements == 0) {
2707     indent[0] = '\0';
2708        } else if (insertHere == 0) {
2709     indent[0] = kw->nextChar;
2710        } else if (kw->separatorChar != '\0') {
2711     indent[0] = kw->separatorChar;
2712        } else {
2713     indent[0] = ' ';
2714        }
2715    
2716        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2717     /* move the end-of-line forward */
2718     line->elements[insertHere].indent =
2719        line->elements[insertHere-1].indent;
2720     line->elements[insertHere-1].indent = strdup(indent);
2721        } else {
2722     line->elements[insertHere].indent = strdup(indent);
2723        }
2724    
2725        line->numElements++;
2726    
2727        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2728          line->elements[0].item,
2729          line->elements[insertHere].item,
2730          line->elements[insertHere].indent,
2731          insertHere);
2732    }
2733    
2734    static void removeElement(struct singleLine * line, int removeHere) {
2735        int i;
2736    
2737        /* sanity check */
2738        if (removeHere >= line->numElements) return;
2739    
2740        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2741          removeHere, line->elements[removeHere].item);
2742    
2743        free(line->elements[removeHere].item);
2744    
2745        if (removeHere > 1) {
2746     /* previous argument gets this argument's post-indentation */
2747     free(line->elements[removeHere-1].indent);
2748     line->elements[removeHere-1].indent =
2749        line->elements[removeHere].indent;
2750        } else {
2751     free(line->elements[removeHere].indent);
2752        }
2753    
2754        /* now collapse the array, but don't bother to realloc smaller */
2755        for (i = removeHere; i < line->numElements - 1; i++)
2756     line->elements[i] = line->elements[i + 1];
2757    
2758        line->numElements--;
2759    }
2760    
2761  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2762      char * first, * second;      char * first, * second;
2763      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2780  int updateActualImage(struct grubConfig
2780      struct singleEntry * entry;      struct singleEntry * entry;
2781      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2782      int index = 0;      int index = 0;
2783      int i, j, k;      int i, k;
2784      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2785      const char ** arg;      const char ** arg;
2786      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2787      int firstElement;      int firstElement;
2788      int *usedElements, *usedArgs;      int *usedElements;
2789        int doreplace;
2790    
2791      if (!image) return 0;      if (!image) return 0;
2792    
# Line 1609  int updateActualImage(struct grubConfig Line 2813  int updateActualImage(struct grubConfig
2813   }   }
2814      }      }
2815    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2816    
2817      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2818   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2819    
2820      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2821   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2822    
2823      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2824    
2825      k = 0;   if (multibootArgs && !entry->multiboot)
2826      for (arg = newArgs; *arg; arg++)      continue;
2827          k++;  
2828      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2829     * LT_KERNELARGS, use that.  Otherwise use
2830     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2831     */
2832     if (useKernelArgs) {
2833        line = getLineByType(LT_KERNELARGS, entry->lines);
2834        if (!line) {
2835     /* no LT_KERNELARGS, need to add it */
2836     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2837           cfg->secondaryIndent, NULL);
2838        }
2839        firstElement = 1;
2840    
2841      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2842   index++;      line = getLineByType(LT_HYPER, entry->lines);
2843        if (!line) {
2844     /* a multiboot entry without LT_HYPER? */
2845     continue;
2846        }
2847        firstElement = 2;
2848    
2849   line = entry->lines;   } else {
2850   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
2851   if (!line) continue;      if (!line) {
2852   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2853     continue;
2854          if (entry->multiboot && !multibootArgs) {      }
2855              /* 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;  
2856   }   }
2857    
2858   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2859      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2860      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2861     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2862        /* this is a multiboot entry, make sure there's
2863         * -- on the args line
2864         */
2865        for (i = firstElement; i < line->numElements; i++) {
2866     if (!strcmp(line->elements[i].item, "--"))
2867        break;
2868        }
2869        if (i == line->numElements) {
2870     /* assume all existing args are kernel args,
2871     * prepend -- to make it official
2872     */
2873     insertElement(line, "--", firstElement, cfg->cfi);
2874     i = firstElement;
2875        }
2876        if (!multibootArgs) {
2877     /* kernel args start after the -- */
2878     firstElement = i + 1;
2879        }
2880     } else if (cfg->cfi->mbConcatArgs) {
2881        /* this is a non-multiboot entry, remove hyper args */
2882        for (i = firstElement; i < line->numElements; i++) {
2883     if (!strcmp(line->elements[i].item, "--"))
2884        break;
2885        }
2886        if (i < line->numElements) {
2887     /* remove args up to -- */
2888     while (strcmp(line->elements[firstElement].item, "--"))
2889        removeElement(line, firstElement);
2890     /* remove -- */
2891     removeElement(line, firstElement);
2892        }
2893   }   }
2894    
2895          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2896    
2897          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2898   for (arg = newArgs; *arg; arg++) {  
2899              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2900      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2901     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2902        !strcmp(line->elements[i].item, "--"))
2903     {
2904        /* reached the end of hyper args, insert here */
2905        doreplace = 0;
2906        break;  
2907     }
2908                  if (usedElements[i])                  if (usedElements[i])
2909                      continue;                      continue;
2910   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2911                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2912      break;      break;
2913                  }                  }
2914              }              }
     chptr = strchr(*arg, '=');  
2915    
2916      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2917   /* replace */   /* direct replacement */
2918   free(line->elements[i].item);   free(line->elements[i].item);
2919   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("");  
  }  
2920    
2921   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2922   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2923      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2924   /* append */   if (rootLine) {
2925   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2926   (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(" ");  
2927   } else {   } else {
2928      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2929         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2930   }   }
2931        }
2932    
2933   line->numElements++;      else {
2934     /* insert/append */
2935     insertElement(line, *arg, i, cfg->cfi);
2936     usedElements = realloc(usedElements, line->numElements *
2937           sizeof(*usedElements));
2938     memmove(&usedElements[i + 1], &usedElements[i],
2939     line->numElements - i - 1);
2940     usedElements[i] = 1;
2941    
2942   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2943     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2944     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2945   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2946      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2947      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2948   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2949   }   }
2950      }      }
             k++;  
2951   }   }
2952    
2953          free(usedElements);          free(usedElements);
2954    
  /* 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? */  
2955   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2956      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2957   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2958        !strcmp(line->elements[i].item, "--"))
2959        /* reached the end of hyper args, stop here */
2960        break;
2961     if (!argMatch(line->elements[i].item, *arg)) {
2962        removeElement(line, i);
2963      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;  
2964   }   }
2965        }
2966   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2967        if (useRoot && !strncmp(*arg, "root=", 5)) {
2968   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
2969      line->elements[j - 1] = line->elements[j];   if (rootLine)
2970        removeLine(entry, rootLine);
  line->numElements--;  
2971      }      }
2972   }   }
2973    
# Line 1760  int updateActualImage(struct grubConfig Line 2978  int updateActualImage(struct grubConfig
2978   }   }
2979      }      }
2980    
     free(usedArgs);  
2981      free(newArgs);      free(newArgs);
2982      free(oldArgs);      free(oldArgs);
2983    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3003  int updateImage(struct grubConfig * cfg,
3003      return rc;      return rc;
3004  }  }
3005    
3006    int updateInitrd(struct grubConfig * cfg, const char * image,
3007                     const char * prefix, const char * initrd) {
3008        struct singleEntry * entry;
3009        struct singleLine * line, * kernelLine, *endLine = NULL;
3010        int index = 0;
3011    
3012        if (!image) return 0;
3013    
3014        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3015            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3016            if (!kernelLine) continue;
3017    
3018            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3019            if (line)
3020                removeLine(entry, line);
3021            if (prefix) {
3022                int prefixLen = strlen(prefix);
3023                if (!strncmp(initrd, prefix, prefixLen))
3024                    initrd += prefixLen;
3025            }
3026     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3027     if (endLine)
3028        removeLine(entry, endLine);
3029            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3030     kernelLine->indent, initrd);
3031            if (!line)
3032        return 1;
3033     if (endLine) {
3034        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3035                if (!line)
3036     return 1;
3037     }
3038    
3039            break;
3040        }
3041    
3042        return 0;
3043    }
3044    
3045  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3046      int fd;      int fd;
3047      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3065  int checkDeviceBootloader(const char * d
3065      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3066   return 0;   return 0;
3067    
3068      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3069   offset = boot[2] + 2;   offset = boot[2] + 2;
3070      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3071   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3072      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3073   offset = boot[1] + 2;        offset = boot[1] + 2;
3074            /*
3075     * it looks like grub, when copying stage1 into the mbr, patches stage1
3076     * right after the JMP location, replacing other instructions such as
3077     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3078     * different bytes.
3079     */
3080          if ((bootSect[offset + 1] == NOOP_OPCODE)
3081      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3082     offset = offset + 3;
3083          }
3084      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3085   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3086      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3222  int checkForLilo(struct grubConfig * con
3222      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3223  }  }
3224    
3225    int checkForGrub2(struct grubConfig * config) {
3226        if (!access("/etc/grub.d/", R_OK))
3227     return 2;
3228    
3229        return 1;
3230    }
3231    
3232  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3233      int fd;      int fd;
3234      unsigned char bootSect[512];      unsigned char bootSect[512];
3235      char * boot;      char * boot;
3236        int onSuse = isSuseSystem();
3237    
3238      if (parseSysconfigGrub(NULL, &boot))  
3239   return 0;      if (onSuse) {
3240     if (parseSuseGrubConf(NULL, &boot))
3241        return 0;
3242        } else {
3243     if (parseSysconfigGrub(NULL, &boot))
3244        return 0;
3245        }
3246    
3247      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3248      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3256  int checkForGrub(struct grubConfig * con
3256      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3257   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3258   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3259     close(fd);
3260   return 1;   return 1;
3261      }      }
3262      close(fd);      close(fd);
3263    
3264        /* The more elaborate checks do not work on SuSE. The checks done
3265         * seem to be reasonble (at least for now), so just return success
3266         */
3267        if (onSuse)
3268     return 2;
3269    
3270      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3271  }  }
3272    
3273    int checkForExtLinux(struct grubConfig * config) {
3274        int fd;
3275        unsigned char bootSect[512];
3276        char * boot;
3277        char executable[] = "/boot/extlinux/extlinux";
3278    
3279        printf("entered: checkForExtLinux()\n");
3280    
3281        if (parseSysconfigGrub(NULL, &boot))
3282     return 0;
3283    
3284        /* assume grub is not installed -- not an error condition */
3285        if (!boot)
3286     return 0;
3287    
3288        fd = open(executable, O_RDONLY);
3289        if (fd < 0)
3290     /* this doesn't exist if grub hasn't been installed */
3291     return 0;
3292    
3293        if (read(fd, bootSect, 512) != 512) {
3294     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3295     executable, strerror(errno));
3296     return 1;
3297        }
3298        close(fd);
3299    
3300        return checkDeviceBootloader(boot, bootSect);
3301    }
3302    
3303    int checkForYaboot(struct grubConfig * config) {
3304        /*
3305         * This is a simplistic check that we consider good enough for own puporses
3306         *
3307         * If we were to properly check if yaboot is *installed* we'd need to:
3308         * 1) get the system boot device (LT_BOOT)
3309         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3310         *    the content on the boot device
3311         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3312         * 4) check again if binary and boot device contents match
3313         */
3314        if (!access("/etc/yaboot.conf", R_OK))
3315     return 2;
3316    
3317        return 1;
3318    }
3319    
3320    int checkForElilo(struct grubConfig * config) {
3321        if (!access("/etc/elilo.conf", R_OK))
3322     return 2;
3323    
3324        return 1;
3325    }
3326    
3327  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3328      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3329    
# Line 1994  static char * getRootSpecifier(char * st Line 3335  static char * getRootSpecifier(char * st
3335      return rootspec;      return rootspec;
3336  }  }
3337    
3338    static char * getInitrdVal(struct grubConfig * config,
3339       const char * prefix, struct singleLine *tmplLine,
3340       const char * newKernelInitrd,
3341       const char ** extraInitrds, int extraInitrdCount)
3342    {
3343        char *initrdVal, *end;
3344        int i;
3345        size_t totalSize;
3346        size_t prefixLen;
3347        char separatorChar;
3348    
3349        prefixLen = strlen(prefix);
3350        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3351    
3352        for (i = 0; i < extraInitrdCount; i++) {
3353     totalSize += sizeof(separatorChar);
3354     totalSize += strlen(extraInitrds[i]) - prefixLen;
3355        }
3356    
3357        initrdVal = end = malloc(totalSize);
3358    
3359        end = stpcpy (end, newKernelInitrd + prefixLen);
3360    
3361        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3362        for (i = 0; i < extraInitrdCount; i++) {
3363     const char *extraInitrd;
3364     int j;
3365    
3366     extraInitrd = extraInitrds[i] + prefixLen;
3367     /* Don't add entries that are already there */
3368     if (tmplLine != NULL) {
3369        for (j = 2; j < tmplLine->numElements; j++)
3370     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3371        break;
3372    
3373        if (j != tmplLine->numElements)
3374     continue;
3375     }
3376    
3377     *end++ = separatorChar;
3378     end = stpcpy(end, extraInitrd);
3379        }
3380    
3381        return initrdVal;
3382    }
3383    
3384  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3385           const char * prefix,           const char * prefix,
3386   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3387   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3388                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3389                     const char * newMBKernel, const char * newMBKernelArgs) {
3390      struct singleEntry * new;      struct singleEntry * new;
3391      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3392      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3393      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3394    
3395      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3396    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3420  int addNewKernel(struct grubConfig * con
3420      config->entries = new;      config->entries = new;
3421    
3422      /* copy/update from the template */      /* copy/update from the template */
3423      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3424        if (newKernelInitrd)
3425     needs |= NEED_INITRD;
3426      if (newMBKernel) {      if (newMBKernel) {
3427          needs |= KERNEL_MB;          needs |= NEED_MB;
3428          new->multiboot = 1;          new->multiboot = 1;
3429      }      }
3430    
3431      if (template) {      if (template) {
3432   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3433      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3434      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3435   indent = tmplLine->indent;   {
3436        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3437    
3438      /* skip comments */      /* skip comments */
3439      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3440      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3441      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3442    
3443      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3444      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3445        /* it's not a multiboot template and this is the kernel
3446              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3447                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3448                  struct singleLine *l;       */
3449                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3450     /* insert the hypervisor first */
3451                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3452                                    config->secondaryIndent,    tmplLine->indent,
3453                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3454                     /* set up for adding the kernel line */
3455                  tmplLine = lastLine;   free(tmplLine->indent);
3456                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3457                      new->lines = l;   needs &= ~NEED_MB;
3458                  } else {      }
3459                      newLine->next = l;      if (needs & NEED_KERNEL) {
3460                      newLine = l;   /* use addLineTmpl to preserve line elements,
3461                  }   * otherwise we could just call addLine.  Unfortunately
3462                  continue;   * this means making some changes to the template
3463              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3464                         template->multiboot && !new->multiboot) {   * change below.
3465                  continue; /* don't need multiboot kernel here */   */
3466              }   struct keywordTypes * mbm_kw =
3467        getKeywordByType(LT_MBMODULE, config->cfi);
3468      if (!new->lines) {   if (mbm_kw) {
3469   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3470   new->lines = newLine;      free(tmplLine->elements[0].item);
3471      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3472   newLine->next = malloc(sizeof(*newLine));   }
3473   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3474      }        newKernelPath + strlen(prefix), config->cfi);
3475     needs &= ~NEED_KERNEL;
3476        }
3477        if (needs & NEED_MB) { /* !mbHyperFirst */
3478     newLine = addLine(new, config->cfi, LT_HYPER,
3479      config->secondaryIndent,
3480      newMBKernel + strlen(prefix));
3481     needs &= ~NEED_MB;
3482        }
3483     } else if (needs & NEED_KERNEL) {
3484        newLine = addLineTmpl(new, tmplLine, newLine,
3485      newKernelPath + strlen(prefix), config->cfi);
3486        needs &= ~NEED_KERNEL;
3487     }
3488    
3489        } else if (tmplLine->type == LT_HYPER &&
3490           tmplLine->numElements >= 2) {
3491     if (needs & NEED_MB) {
3492        newLine = addLineTmpl(new, tmplLine, newLine,
3493      newMBKernel + strlen(prefix), config->cfi);
3494        needs &= ~NEED_MB;
3495     }
3496    
3497      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3498      newLine->next = NULL;         tmplLine->numElements >= 2) {
3499      newLine->type = tmplLine->type;   if (new->multiboot) {
3500      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3501      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3502      newLine->numElements);        newKernelPath +
3503      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3504   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3505   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3506   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3507      }   char *initrdVal;
3508     initrdVal = getInitrdVal(config, prefix, tmplLine,
3509              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3510      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3511                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3512                  if (!template->multiboot) {        initrdVal, config->cfi);
3513                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3514                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3515                  } else {      }
3516                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3517                      repl = newMBKernel;      /* template is multi but new is not,
3518                  }       * insert the kernel in the first module slot
3519                  if (new->multiboot && !template->multiboot) {       */
3520                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3521                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3522                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3523                  }   strdup(getKeywordByType(tmplLine->type,
3524   free(newLine->elements[1].item);   config->cfi)->key);
3525                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3526                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3527                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3528                                                             rootspec,      needs &= ~NEED_KERNEL;
3529                                                             repl +   } else if (needs & NEED_INITRD) {
3530                                                             strlen(prefix));      char *initrdVal;
3531                  } else {      /* template is multi but new is not,
3532                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3533                                                         strlen(prefix));       */
3534                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3535              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3536                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3537                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3538                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3539                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3540                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3541                      newLine->type = LT_KERNEL;      free(initrdVal);
3542                  }      needs &= ~NEED_INITRD;
3543   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;  
3544    
3545   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3546      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3547      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3548        config->cfi->mbInitRdIsModule) {
3549        /* make sure we don't insert the module initrd
3550         * before the module kernel... if we don't do it here,
3551         * it will be inserted following the template.
3552         */
3553        if (!needs & NEED_KERNEL) {
3554     char *initrdVal;
3555    
3556     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3557     newLine = addLine(new, config->cfi, LT_MBMODULE,
3558      config->secondaryIndent,
3559      initrdVal);
3560     free(initrdVal);
3561     needs &= ~NEED_INITRD;
3562        }
3563     } else if (needs & NEED_INITRD) {
3564        char *initrdVal;
3565        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3566        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3567        free(initrdVal);
3568        needs &= ~NEED_INITRD;
3569   }   }
3570    
3571   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3572   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3573   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3574     char *nkt = malloc(strlen(newKernelTitle)+3);
3575     strcpy(nkt, "'");
3576     strcat(nkt, newKernelTitle);
3577     strcat(nkt, "'");
3578     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3579     free(nkt);
3580     needs &= ~NEED_TITLE;
3581      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3582                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3583                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3584                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3585                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3586                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3587                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3588                                             newLine->numElements);     config->cfi->titleBracketed) {
3589        /* addLineTmpl doesn't handle titleBracketed */
3590                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3591                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3592                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3593                  newLine->numElements = 1;   }
3594              }      } else if (tmplLine->type == LT_ECHO) {
3595        requote(tmplLine, config->cfi);
3596        static const char *prefix = "'Loading ";
3597        if (tmplLine->numElements > 1 &&
3598        strstr(tmplLine->elements[1].item, prefix) &&
3599        masterLine->next &&
3600        iskernel(masterLine->next->type)) {
3601     char *newTitle = malloc(strlen(prefix) +
3602     strlen(newKernelTitle) + 2);
3603    
3604     strcpy(newTitle, prefix);
3605     strcat(newTitle, newKernelTitle);
3606     strcat(newTitle, "'");
3607     newLine = addLine(new, config->cfi, LT_ECHO,
3608     tmplLine->indent, newTitle);
3609     free(newTitle);
3610        } else {
3611     /* pass through other lines from the template */
3612     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3613     config->cfi);
3614        }
3615        } else {
3616     /* pass through other lines from the template */
3617     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3618        }
3619   }   }
3620    
3621      } else {      } else {
3622   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3623      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3624     */
3625     switch (config->cfi->entryStart) {
3626        case LT_KERNEL:
3627        case LT_KERNEL_EFI:
3628     if (new->multiboot && config->cfi->mbHyperFirst) {
3629        /* fall through to LT_HYPER */
3630     } else {
3631        newLine = addLine(new, config->cfi,
3632              preferredLineType(LT_KERNEL, config->cfi),
3633          config->primaryIndent,
3634          newKernelPath + strlen(prefix));
3635        needs &= ~NEED_KERNEL;
3636        break;
3637     }
3638    
3639        case LT_HYPER:
3640     newLine = addLine(new, config->cfi, LT_HYPER,
3641      config->primaryIndent,
3642      newMBKernel + strlen(prefix));
3643     needs &= ~NEED_MB;
3644   break;   break;
         }  
3645    
3646   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3647      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3648       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3649       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3650      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3651       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3652      default:        config->primaryIndent, nkt);
3653                  /* zipl strikes again */   free(nkt);
3654                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3655                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3656                      chptr = newKernelTitle;   break;
3657                      type = LT_TITLE;      }
3658                      break;      case LT_TITLE:
3659                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3660                      abort();   char * templabel;
3661                  }   int x = 0, y = 0;
3662   }  
3663     templabel = strdup(newKernelTitle);
3664     while( templabel[x]){
3665     if( templabel[x] == ' ' ){
3666     y = x;
3667     while( templabel[y] ){
3668     templabel[y] = templabel[y+1];
3669     y++;
3670     }
3671     }
3672     x++;
3673     }
3674     newLine = addLine(new, config->cfi, LT_TITLE,
3675      config->primaryIndent, templabel);
3676     free(templabel);
3677     }else{
3678     newLine = addLine(new, config->cfi, LT_TITLE,
3679      config->primaryIndent, newKernelTitle);
3680     }
3681     needs &= ~NEED_TITLE;
3682     break;
3683    
3684   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3685   new->lines = newLine;   abort();
3686     }
3687      }      }
3688    
3689      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3690          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3691              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3692                                config->secondaryIndent,       */
3693                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3694          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3695              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3696                                config->secondaryIndent,    newKernelTitle);
3697                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3698          /* don't need to check for title as it's guaranteed to have been      }
3699           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3700           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3701          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3702              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3703                                config->secondaryIndent,   needs &= ~NEED_MB;
3704                                newKernelInitrd + strlen(prefix));      }
3705      } else {      if (needs & NEED_KERNEL) {
3706          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3707              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3708                                config->secondaryIndent,        config->cfi))
3709                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3710          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3711              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3712                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3713                                newKernelTitle);   needs &= ~NEED_KERNEL;
3714          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3715              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3716                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3717                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3718      newMBKernel + strlen(prefix));
3719     needs &= ~NEED_MB;
3720        }
3721        if (needs & NEED_INITRD) {
3722     char *initrdVal;
3723     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3724     newLine = addLine(new, config->cfi,
3725      (new->multiboot && getKeywordByType(LT_MBMODULE,
3726          config->cfi))
3727       ? LT_MBMODULE
3728       : preferredLineType(LT_INITRD, config->cfi),
3729      config->secondaryIndent,
3730      initrdVal);
3731     free(initrdVal);
3732     needs &= ~NEED_INITRD;
3733        }
3734        if (needs & NEED_END) {
3735     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3736     config->secondaryIndent, NULL);
3737     needs &= ~NEED_END;
3738        }
3739    
3740        if (needs) {
3741     printf(_("grubby: needs=%d, aborting\n"), needs);
3742     abort();
3743      }      }
3744    
3745      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3748  int addNewKernel(struct grubConfig * con
3748      return 0;      return 0;
3749  }  }
3750    
3751    static void traceback(int signum)
3752    {
3753        void *array[40];
3754        size_t size;
3755    
3756        signal(SIGSEGV, SIG_DFL);
3757        memset(array, '\0', sizeof (array));
3758        size = backtrace(array, 40);
3759    
3760        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
3761                (unsigned long)size);
3762        backtrace_symbols_fd(array, size, STDERR_FILENO);
3763        exit(1);
3764    }
3765    
3766  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3767      poptContext optCon;      poptContext optCon;
3768      char * grubConfig = NULL;      const char * grubConfig = NULL;
3769      char * outputFile = NULL;      char * outputFile = NULL;
3770      int arg = 0;      int arg = 0;
3771      int flags = 0;      int flags = 0;
3772      int badImageOkay = 0;      int badImageOkay = 0;
3773        int configureGrub2 = 0;
3774      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3775      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3776        int configureExtLinux = 0;
3777      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3778        int extraInitrdCount = 0;
3779      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3780      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3781      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3791  int main(int argc, const char ** argv) {
3791      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3792      char * removeArgs = NULL;      char * removeArgs = NULL;
3793      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3794        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3795      const char * chptr = NULL;      const char * chptr = NULL;
3796      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3797      struct grubConfig * config;      struct grubConfig * config;
3798      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3799      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3800      int displayDefault = 0;      int displayDefault = 0;
3801        int displayDefaultIndex = 0;
3802        int displayDefaultTitle = 0;
3803        int defaultIndex = -1;
3804      struct poptOption options[] = {      struct poptOption options[] = {
3805   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3806      _("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 3818  int main(int argc, const char ** argv) {
3818   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3819      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3820      _("bootfs") },      _("bootfs") },
3821  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3822   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3823      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3824  #endif  #endif
3825   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3826      _("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 3831  int main(int argc, const char ** argv) {
3831        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3832        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3833        "template"), NULL },        "template"), NULL },
3834     { "debug", 0, 0, &debug, 0,
3835        _("print debugging information for failures") },
3836   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3837      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3838     { "default-index", 0, 0, &displayDefaultIndex, 0,
3839        _("display the index of the default kernel") },
3840     { "default-title", 0, 0, &displayDefaultTitle, 0,
3841        _("display the title of the default kernel") },
3842   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3843      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3844     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
3845        _("force grub2 stanzas to use efi") },
3846     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3847        _("configure extlinux bootloader (from syslinux)") },
3848   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3849      _("configure grub bootloader") },      _("configure grub bootloader") },
3850     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3851        _("configure grub2 bootloader") },
3852   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3853      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3854      _("kernel-path") },      _("kernel-path") },
3855   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3856      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3857     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3858        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
3859   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3860      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3861   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3875  int main(int argc, const char ** argv) {
3875   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3876      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3877        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3878     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3879        _("make the given entry index the default entry"),
3880        _("entry-index") },
3881   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3882      _("configure silo bootloader") },      _("configure silo bootloader") },
3883   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3895  int main(int argc, const char ** argv) {
3895   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3896      };      };
3897    
3898        useextlinuxmenu=0;
3899    
3900        signal(SIGSEGV, traceback);
3901    
3902      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3903      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3904    
# Line 2391  int main(int argc, const char ** argv) { Line 3908  int main(int argc, const char ** argv) {
3908      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3909      exit(0);      exit(0);
3910      break;      break;
3911      case 'i':
3912        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3913         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3914        } else {
3915     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3916     return 1;
3917        }
3918        break;
3919   }   }
3920      }      }
3921    
# Line 2406  int main(int argc, const char ** argv) { Line 3931  int main(int argc, const char ** argv) {
3931   return 1;   return 1;
3932      }      }
3933    
3934      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3935   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3936     configureExtLinux ) > 1) {
3937   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3938   return 1;   return 1;
3939      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3940   fprintf(stderr,   fprintf(stderr,
3941      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3942   return 1;   return 1;
3943        } else if (configureGrub2) {
3944     cfi = &grub2ConfigType;
3945      } else if (configureLilo) {      } else if (configureLilo) {
3946   cfi = &liloConfigType;   cfi = &liloConfigType;
3947      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 3954  int main(int argc, const char ** argv) {
3954          cfi = &siloConfigType;          cfi = &siloConfigType;
3955      } else if (configureZipl) {      } else if (configureZipl) {
3956          cfi = &ziplConfigType;          cfi = &ziplConfigType;
3957        } else if (configureExtLinux) {
3958     cfi = &extlinuxConfigType;
3959     useextlinuxmenu=1;
3960      }      }
3961    
3962      if (!cfi) {      if (!cfi) {
3963            if (grub2FindConfig(&grub2ConfigType))
3964        cfi = &grub2ConfigType;
3965     else
3966        #ifdef __ia64__        #ifdef __ia64__
3967   cfi = &eliloConfigType;      cfi = &eliloConfigType;
3968        #elif __powerpc__        #elif __powerpc__
3969   cfi = &yabootConfigType;      cfi = &yabootConfigType;
3970        #elif __sparc__        #elif __sparc__
3971          cfi = &siloConfigType;              cfi = &siloConfigType;
3972        #elif __s390__        #elif __s390__
3973          cfi = &ziplConfigType;              cfi = &ziplConfigType;
3974        #elif __s390x__        #elif __s390x__
3975          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
3976        #else        #else
3977   cfi = &grubConfigType;      cfi = &grubConfigType;
3978        #endif        #endif
3979      }      }
3980    
3981      if (!grubConfig)      if (!grubConfig) {
3982   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
3983        grubConfig = cfi->findConfig(cfi);
3984     if (!grubConfig)
3985        grubConfig = cfi->defaultConfig;
3986        }
3987    
3988      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
3989    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
3990    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
3991        (defaultIndex >= 0))) {
3992   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
3993    "specified option"));    "specified option"));
3994   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4004  int main(int argc, const char ** argv) {
4004      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4005   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4006   return 1;   return 1;
4007      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4008    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4009    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4010   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4011   return 1;   return 1;
4012      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4030  int main(int argc, const char ** argv) {
4030   makeDefault = 1;   makeDefault = 1;
4031   defaultKernel = NULL;   defaultKernel = NULL;
4032      }      }
4033        else if (defaultKernel && (defaultIndex >= 0)) {
4034     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4035      "may not be used together\n"));
4036     return 1;
4037        }
4038    
4039      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4040   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4041   "is used\n"));   "is used\n"));
4042   return 1;   return 1;
4043      }      }
4044    
4045      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4046   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4047          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4048     && (defaultIndex == -1)) {
4049   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4050   return 1;   return 1;
4051      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4065  int main(int argc, const char ** argv) {
4065   bootPrefix = "";   bootPrefix = "";
4066      }      }
4067    
4068        if (!cfi->mbAllowExtraInitRds &&
4069     extraInitrdCount > 0) {
4070     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4071     return 1;
4072        }
4073    
4074      if (bootloaderProbe) {      if (bootloaderProbe) {
4075   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4076   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4077    
4078   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grub2config = grub2FindConfig(&grub2ConfigType);
4079      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (grub2config) {
4080        gconfig = readConfig(grub2config, &grub2ConfigType);
4081        if (!gconfig)
4082     gr2c = 1;
4083        else
4084     gr2c = checkForGrub2(gconfig);
4085     }
4086    
4087     const char *grubconfig = grubFindConfig(&grubConfigType);
4088     if (!access(grubconfig, F_OK)) {
4089        gconfig = readConfig(grubconfig, &grubConfigType);
4090      if (!gconfig)      if (!gconfig)
4091   grc = 1;   grc = 1;
4092      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4101  int main(int argc, const char ** argv) {
4101   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4102   }   }
4103    
4104   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4105        econfig = readConfig(eliloConfigType.defaultConfig,
4106     &eliloConfigType);
4107        if (!econfig)
4108     erc = 1;
4109        else
4110     erc = checkForElilo(econfig);
4111     }
4112    
4113     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4114        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4115        if (!lconfig)
4116     extrc = 1;
4117        else
4118     extrc = checkForExtLinux(lconfig);
4119     }
4120    
4121    
4122     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4123        yconfig = readConfig(yabootConfigType.defaultConfig,
4124     &yabootConfigType);
4125        if (!yconfig)
4126     yrc = 1;
4127        else
4128     yrc = checkForYaboot(yconfig);
4129     }
4130    
4131     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4132     erc == 1)
4133        return 1;
4134    
4135   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4136     if (gr2c == 2) printf("grub2\n");
4137   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4138     if (extrc == 2) printf("extlinux\n");
4139     if (yrc == 2) printf("yaboot\n");
4140     if (erc == 2) printf("elilo\n");
4141    
4142   return 0;   return 0;
4143      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4155  int main(int argc, const char ** argv) {
4155   if (!entry) return 0;   if (!entry) return 0;
4156   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4157    
4158   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4159   if (!line) return 0;   if (!line) return 0;
4160    
4161          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4163  int main(int argc, const char ** argv) {
4163                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4164    
4165   return 0;   return 0;
4166    
4167        } else if (displayDefaultTitle) {
4168     struct singleLine * line;
4169     struct singleEntry * entry;
4170    
4171     if (config->defaultImage == -1) return 0;
4172     entry = findEntryByIndex(config, config->defaultImage);
4173     if (!entry) return 0;
4174    
4175     if (!configureGrub2) {
4176      line = getLineByType(LT_TITLE, entry->lines);
4177      if (!line) return 0;
4178      printf("%s\n", line->elements[1].item);
4179    
4180     } else {
4181      char * title;
4182    
4183      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4184      line = getLineByType(LT_MENUENTRY, entry->lines);
4185      if (!line) return 0;
4186      title = grub2ExtractTitle(line);
4187      if (title)
4188        printf("%s\n", title);
4189     }
4190     return 0;
4191    
4192        } else if (displayDefaultIndex) {
4193            if (config->defaultImage == -1) return 0;
4194            printf("%i\n", config->defaultImage);
4195    
4196      } else if (kernelInfo)      } else if (kernelInfo)
4197   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4198    
# Line 2581  int main(int argc, const char ** argv) { Line 4204  int main(int argc, const char ** argv) {
4204      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4205      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4206      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4207      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4208      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4209      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4210                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4211        if (updateKernelPath && newKernelInitrd) {
4212                if (updateInitrd(config, updateKernelPath, bootPrefix,
4213                                 newKernelInitrd)) return 1;
4214        }
4215      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4216                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4217                         (const char **)extraInitrds, extraInitrdCount,
4218                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4219            
4220    
# Line 2597  int main(int argc, const char ** argv) { Line 4225  int main(int argc, const char ** argv) {
4225      }      }
4226    
4227      if (!outputFile)      if (!outputFile)
4228   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4229    
4230      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4231  }  }

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