Magellan Linux

Diff of /tags/grubby-8_40_20170706/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 2236 by niro, Mon Oct 21 13:19:07 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    #include "log.h"
40    
41    #ifndef DEBUG
42    #define DEBUG 0
43    #endif
44    
45    #if DEBUG
46    #define dbgPrintf(format, args...) fprintf(stderr, format , ## args)
47    #else
48    #define dbgPrintf(format, args...)
49    #endif
50    
51  #include "mount_by_label.h"  int debug = 0; /* Currently just for template debugging */
52    
53  #define _(A) (A)  #define _(A) (A)
54    
55    #define MAX_EXTRA_INITRDS  16 /* code segment checked by --bootloader-probe */
56  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */  #define CODE_SEG_SIZE  128 /* code segment checked by --bootloader-probe */
57    
58    #define NOOP_OPCODE 0x90
59    #define JMP_SHORT_OPCODE 0xeb
60    
61    int isEfi = 0;
62    
63    char *saved_command_line = NULL;
64    
65  /* comments get lumped in with indention */  /* comments get lumped in with indention */
66  struct lineElement {  struct lineElement {
67      char * item;      char * item;
68      char * indent;      char * indent;
69  };  };
70    
71  enum lineType_e { LT_WHITESPACE, LT_TITLE, LT_KERNEL, LT_INITRD, LT_DEFAULT,  enum lineType_e {
72         LT_UNKNOWN, LT_ROOT, LT_FALLBACK, LT_KERNELARGS, LT_BOOT,      LT_WHITESPACE   = 1 << 0,
73         LT_BOOTROOT, LT_LBA, LT_MBMODULE, LT_OTHER, LT_GENERIC };      LT_TITLE        = 1 << 1,
74        LT_KERNEL       = 1 << 2,
75        LT_INITRD       = 1 << 3,
76        LT_HYPER        = 1 << 4,
77        LT_DEFAULT      = 1 << 5,
78        LT_MBMODULE     = 1 << 6,
79        LT_ROOT         = 1 << 7,
80        LT_FALLBACK     = 1 << 8,
81        LT_KERNELARGS   = 1 << 9,
82        LT_BOOT         = 1 << 10,
83        LT_BOOTROOT     = 1 << 11,
84        LT_LBA          = 1 << 12,
85        LT_OTHER        = 1 << 13,
86        LT_GENERIC      = 1 << 14,
87        LT_ECHO    = 1 << 16,
88        LT_MENUENTRY    = 1 << 17,
89        LT_ENTRY_END    = 1 << 18,
90        LT_SET_VARIABLE = 1 << 19,
91        LT_KERNEL_EFI   = 1 << 20,
92        LT_INITRD_EFI   = 1 << 21,
93        LT_UNKNOWN      = 1 << 22,
94    };
95    
96  struct singleLine {  struct singleLine {
97      char * indent;      char * indent;
# Line 61  struct singleEntry { Line 112  struct singleEntry {
112    
113  #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 */
114    
115  #define KERNEL_KERNEL    (1 << 0)  /* These defines are (only) used in addNewKernel() */
116  #define KERNEL_INITRD    (1 << 2)  #define NEED_KERNEL  (1 << 0)
117  #define KERNEL_TITLE    (1 << 3)  #define NEED_INITRD  (1 << 1)
118  #define KERNEL_ARGS    (1 << 4)  #define NEED_TITLE   (1 << 2)
119  #define KERNEL_MB           (1 << 5)  #define NEED_ARGS    (1 << 3)
120    #define NEED_MB      (1 << 4)
121    #define NEED_END     (1 << 5)
122    
123  #define MAIN_DEFAULT    (1 << 0)  #define MAIN_DEFAULT    (1 << 0)
124  #define DEFAULT_SAVED       -2  #define DEFAULT_SAVED       -2
125    #define DEFAULT_SAVED_GRUB2 -3
126    
127  struct keywordTypes {  struct keywordTypes {
128      char * key;      char * key;
129      enum lineType_e type;      enum lineType_e type;
130      char nextChar;      char nextChar;
131  } ;      char separatorChar;
132    };
133    
134    struct configFileInfo;
135    
136    typedef const char *(*findConfigFunc)(struct configFileInfo *);
137    typedef const int (*writeLineFunc)(struct configFileInfo *,
138     struct singleLine *line);
139    
140  struct configFileInfo {  struct configFileInfo {
141      char * defaultConfig;      char * defaultConfig;
142        findConfigFunc findConfig;
143        writeLineFunc writeLine;
144      struct keywordTypes * keywords;      struct keywordTypes * keywords;
145        int caseInsensitive;
146      int defaultIsIndex;      int defaultIsIndex;
147        int defaultIsVariable;
148      int defaultSupportSaved;      int defaultSupportSaved;
149      enum lineType_e entrySeparator;      enum lineType_e entryStart;
150        enum lineType_e entryEnd;
151      int needsBootPrefix;      int needsBootPrefix;
152      int argsInQuotes;      int argsInQuotes;
153      int maxTitleLength;      int maxTitleLength;
154      int titleBracketed;      int titleBracketed;
155        int titlePosition;
156        int mbHyperFirst;
157        int mbInitRdIsModule;
158        int mbConcatArgs;
159        int mbAllowExtraInitRds;
160  };  };
161    
162  struct keywordTypes grubKeywords[] = {  struct keywordTypes grubKeywords[] = {
# Line 94  struct keywordTypes grubKeywords[] = { Line 165  struct keywordTypes grubKeywords[] = {
165      { "default",    LT_DEFAULT,    ' ' },      { "default",    LT_DEFAULT,    ' ' },
166      { "fallback",   LT_FALLBACK,    ' ' },      { "fallback",   LT_FALLBACK,    ' ' },
167      { "kernel",    LT_KERNEL,    ' ' },      { "kernel",    LT_KERNEL,    ' ' },
168      { "initrd",    LT_INITRD,    ' ' },      { "initrd",    LT_INITRD,    ' ', ' ' },
169      { "module",     LT_MBMODULE,    ' ' },      { "module",     LT_MBMODULE,    ' ' },
170        { "kernel",     LT_HYPER,       ' ' },
171      { NULL,    0, 0 },      { NULL,    0, 0 },
172  };  };
173    
174    const char *grubFindConfig(struct configFileInfo *cfi) {
175        static const char *configFiles[] = {
176     "/boot/grub/grub.conf",
177     "/boot/grub/menu.lst",
178     "/etc/grub.conf",
179     NULL
180        };
181        static int i = -1;
182    
183        if (i == -1) {
184     for (i = 0; configFiles[i] != NULL; i++) {
185        dbgPrintf("Checking \"%s\": ", configFiles[i]);
186        if (!access(configFiles[i], R_OK)) {
187     dbgPrintf("found\n");
188     return configFiles[i];
189        }
190        dbgPrintf("not found\n");
191     }
192        }
193        return configFiles[i];
194    }
195    
196  struct configFileInfo grubConfigType = {  struct configFileInfo grubConfigType = {
197      "/boot/grub/grub.conf",    /* defaultConfig */      .findConfig = grubFindConfig,
198      grubKeywords,    /* keywords */      .keywords = grubKeywords,
199      1,    /* defaultIsIndex */      .defaultIsIndex = 1,
200      1,    /* defaultSupportSaved */      .defaultSupportSaved = 1,
201      LT_TITLE,    /* entrySeparator */      .entryStart = LT_TITLE,
202      1,    /* needsBootPrefix */      .needsBootPrefix = 1,
203      0,    /* argsInQuotes */      .mbHyperFirst = 1,
204      0,    /* maxTitleLength */      .mbInitRdIsModule = 1,
205      0,                                      /* titleBracketed */      .mbAllowExtraInitRds = 1,
206    };
207    
208    struct keywordTypes grub2Keywords[] = {
209        { "menuentry",  LT_MENUENTRY,   ' ' },
210        { "}",          LT_ENTRY_END,   ' ' },
211        { "echo",       LT_ECHO,        ' ' },
212        { "set",        LT_SET_VARIABLE,' ', '=' },
213        { "root",       LT_BOOTROOT,    ' ' },
214        { "default",    LT_DEFAULT,     ' ' },
215        { "fallback",   LT_FALLBACK,    ' ' },
216        { "linux",      LT_KERNEL,      ' ' },
217        { "linuxefi",   LT_KERNEL_EFI,  ' ' },
218        { "initrd",     LT_INITRD,      ' ', ' ' },
219        { "initrdefi",  LT_INITRD_EFI,  ' ', ' ' },
220        { "module",     LT_MBMODULE,    ' ' },
221        { "kernel",     LT_HYPER,       ' ' },
222        { NULL, 0, 0 },
223    };
224    
225    const char *grub2FindConfig(struct configFileInfo *cfi) {
226        static const char *configFiles[] = {
227     "/boot/grub/grub-efi.cfg",
228     "/boot/grub/grub.cfg",
229     NULL
230        };
231        static int i = -1;
232        static const char *grub_cfg = "/boot/grub/grub.cfg";
233    
234        if (i == -1) {
235     for (i = 0; configFiles[i] != NULL; i++) {
236        dbgPrintf("Checking \"%s\": ", configFiles[i]);
237        if (!access(configFiles[i], R_OK)) {
238     dbgPrintf("found\n");
239     return configFiles[i];
240        }
241     }
242        }
243    
244        /* Ubuntu renames grub2 to grub, so check for the grub.d directory
245         * that isn't in grub1, and if it exists, return the config file path
246         * that they use. */
247        if (configFiles[i] == NULL && !access("/etc/grub.d/", R_OK)) {
248     dbgPrintf("found\n");
249     return grub_cfg;
250        }
251    
252        dbgPrintf("not found\n");
253        return configFiles[i];
254    }
255    
256    int sizeOfSingleLine(struct singleLine * line) {
257      int count = 0;
258    
259      for (int i = 0; i < line->numElements; i++) {
260        int indentSize = 0;
261    
262        count = count + strlen(line->elements[i].item);
263    
264        indentSize = strlen(line->elements[i].indent);
265        if (indentSize > 0)
266          count = count + indentSize;
267        else
268          /* be extra safe and add room for whitespaces */
269          count = count + 1;
270      }
271    
272      /* room for trailing terminator */
273      count = count + 1;
274    
275      return count;
276    }
277    
278    static int isquote(char q)
279    {
280        if (q == '\'' || q == '\"')
281     return 1;
282        return 0;
283    }
284    
285    static int iskernel(enum lineType_e type) {
286        return (type == LT_KERNEL || type == LT_KERNEL_EFI);
287    }
288    
289    static int isinitrd(enum lineType_e type) {
290        return (type == LT_INITRD || type == LT_INITRD_EFI);
291    }
292    
293    char *grub2ExtractTitle(struct singleLine * line) {
294        char * current;
295        char * current_indent;
296        int current_len;
297        int current_indent_len;
298        int i;
299    
300        /* bail out if line does not start with menuentry */
301        if (strcmp(line->elements[0].item, "menuentry"))
302          return NULL;
303    
304        i = 1;
305        current = line->elements[i].item;
306        current_len = strlen(current);
307    
308        /* if second word is quoted, strip the quotes and return single word */
309        if (isquote(*current) && isquote(current[current_len - 1])) {
310     char *tmp;
311    
312     tmp = strdup(current);
313     *(tmp + current_len - 1) = '\0';
314     return ++tmp;
315        }
316    
317        /* if no quotes, return second word verbatim */
318        if (!isquote(*current))
319     return current;
320    
321        /* second element start with a quote, so we have to find the element
322         * whose last character is also quote (assuming it's the closing one) */
323        int resultMaxSize;
324        char * result;
325        
326        resultMaxSize = sizeOfSingleLine(line);
327        result = malloc(resultMaxSize);
328        snprintf(result, resultMaxSize, "%s", ++current);
329        
330        i++;
331        for (; i < line->numElements; ++i) {
332     current = line->elements[i].item;
333     current_len = strlen(current);
334     current_indent = line->elements[i].indent;
335     current_indent_len = strlen(current_indent);
336    
337     strncat(result, current_indent, current_indent_len);
338     if (!isquote(current[current_len-1])) {
339        strncat(result, current, current_len);
340     } else {
341        strncat(result, current, current_len - 1);
342        break;
343     }
344        }
345        return result;
346    }
347    
348    struct configFileInfo grub2ConfigType = {
349        .findConfig = grub2FindConfig,
350        .keywords = grub2Keywords,
351        .defaultIsIndex = 1,
352        .defaultSupportSaved = 1,
353        .defaultIsVariable = 1,
354        .entryStart = LT_MENUENTRY,
355        .entryEnd = LT_ENTRY_END,
356        .titlePosition = 1,
357        .needsBootPrefix = 1,
358        .mbHyperFirst = 1,
359        .mbInitRdIsModule = 1,
360        .mbAllowExtraInitRds = 1,
361  };  };
362    
363  struct keywordTypes yabootKeywords[] = {  struct keywordTypes yabootKeywords[] = {
# Line 142  struct keywordTypes yabootKeywords[] = { Line 391  struct keywordTypes yabootKeywords[] = {
391      { "partition",  LT_GENERIC,    '=' },      { "partition",  LT_GENERIC,    '=' },
392      { "device",    LT_GENERIC,    '=' },      { "device",    LT_GENERIC,    '=' },
393      { "fstype",    LT_GENERIC,    '=' },      { "fstype",    LT_GENERIC,    '=' },
394      { "initrd",    LT_INITRD,    '=' },      { "initrd",    LT_INITRD,    '=', ';' },
395      { "append",    LT_KERNELARGS,  '=' },      { "append",    LT_KERNELARGS,  '=' },
396      { "boot",    LT_BOOT,    '=' },      { "boot",    LT_BOOT,    '=' },
397      { "lba",    LT_LBA,    ' ' },      { "lba",    LT_LBA,    ' ' },
# Line 162  struct keywordTypes liloKeywords[] = { Line 411  struct keywordTypes liloKeywords[] = {
411      { NULL,    0, 0 },      { NULL,    0, 0 },
412  };  };
413    
414    struct keywordTypes eliloKeywords[] = {
415        { "label",    LT_TITLE,    '=' },
416        { "root",    LT_ROOT,    '=' },
417        { "default",    LT_DEFAULT,    '=' },
418        { "image",    LT_KERNEL,    '=' },
419        { "initrd",    LT_INITRD,    '=' },
420        { "append",    LT_KERNELARGS,  '=' },
421        { "vmm",    LT_HYPER,       '=' },
422        { NULL,    0, 0 },
423    };
424    
425  struct keywordTypes siloKeywords[] = {  struct keywordTypes siloKeywords[] = {
426      { "label",    LT_TITLE,    '=' },      { "label",    LT_TITLE,    '=' },
427      { "root",    LT_ROOT,    '=' },      { "root",    LT_ROOT,    '=' },
# Line 183  struct keywordTypes ziplKeywords[] = { Line 443  struct keywordTypes ziplKeywords[] = {
443      { NULL,         0, 0 },      { NULL,         0, 0 },
444  };  };
445    
446    struct keywordTypes extlinuxKeywords[] = {
447        { "label",    LT_TITLE,    ' ' },
448        { "root",    LT_ROOT,    ' ' },
449        { "default",    LT_DEFAULT,    ' ' },
450        { "kernel",    LT_KERNEL,    ' ' },
451        { "initrd",    LT_INITRD,      ' ', ',' },
452        { "append",    LT_KERNELARGS,  ' ' },
453        { "prompt",     LT_UNKNOWN,     ' ' },
454        { NULL,    0, 0 },
455    };
456    int useextlinuxmenu;
457  struct configFileInfo eliloConfigType = {  struct configFileInfo eliloConfigType = {
458      "/boot/efi/EFI/redhat/elilo.conf",    /* defaultConfig */      .defaultConfig = "/boot/efi/EFI/redhat/elilo.conf",
459      liloKeywords,    /* keywords */      .keywords = eliloKeywords,
460      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
461      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
462      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
463      1,                    /* needsBootPrefix */      .mbConcatArgs = 1,
     1,    /* argsInQuotes */  
     0,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
464  };  };
465    
466  struct configFileInfo liloConfigType = {  struct configFileInfo liloConfigType = {
467      "/etc/lilo.conf",    /* defaultConfig */      .defaultConfig = "/etc/lilo.conf",
468      liloKeywords,    /* keywords */      .keywords = liloKeywords,
469      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
470      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
471      LT_KERNEL,    /* entrySeparator */      .maxTitleLength = 15,
     0,    /* needsBootPrefix */  
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
472  };  };
473    
474  struct configFileInfo yabootConfigType = {  struct configFileInfo yabootConfigType = {
475      "/etc/yaboot.conf",    /* defaultConfig */      .defaultConfig = "/etc/yaboot.conf",
476      yabootKeywords,    /* keywords */      .keywords = yabootKeywords,
477      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
478      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
479      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
480      1,    /* needsBootPrefix */      .maxTitleLength = 15,
481      1,    /* argsInQuotes */      .mbAllowExtraInitRds = 1,
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
482  };  };
483    
484  struct configFileInfo siloConfigType = {  struct configFileInfo siloConfigType = {
485      "/etc/silo.conf",    /* defaultConfig */      .defaultConfig = "/etc/silo.conf",
486      siloKeywords,    /* keywords */      .keywords = siloKeywords,
487      0,    /* defaultIsIndex */      .entryStart = LT_KERNEL,
488      0,    /* defaultSupportSaved */      .needsBootPrefix = 1,
489      LT_KERNEL,    /* entrySeparator */      .argsInQuotes = 1,
490      1,    /* needsBootPrefix */      .maxTitleLength = 15,
     1,    /* argsInQuotes */  
     15,    /* maxTitleLength */  
     0,                                      /* titleBracketed */  
491  };  };
492    
493  struct configFileInfo ziplConfigType = {  struct configFileInfo ziplConfigType = {
494      "/etc/zipl.conf",    /* defaultConfig */      .defaultConfig = "/etc/zipl.conf",
495      ziplKeywords,    /* keywords */      .keywords = ziplKeywords,
496      0,    /* defaultIsIndex */      .entryStart = LT_TITLE,
497      0,    /* defaultSupportSaved */      .argsInQuotes = 1,
498      LT_TITLE,    /* entrySeparator */      .titleBracketed = 1,
499      0,    /* needsBootPrefix */  };
500      1,    /* argsInQuotes */  
501      15,    /* maxTitleLength */  struct configFileInfo extlinuxConfigType = {
502      1,                                      /* titleBracketed */      .defaultConfig = "/boot/extlinux/extlinux.conf",
503        .keywords = extlinuxKeywords,
504        .caseInsensitive = 1,
505        .entryStart = LT_TITLE,
506        .needsBootPrefix = 1,
507        .maxTitleLength = 255,
508        .mbAllowExtraInitRds = 1,
509  };  };
510    
511  struct grubConfig {  struct grubConfig {
# Line 255  struct grubConfig { Line 520  struct grubConfig {
520      struct configFileInfo * cfi;      struct configFileInfo * cfi;
521  };  };
522    
523    blkid_cache blkid;
524    
525  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);  struct singleEntry * findEntryByIndex(struct grubConfig * cfg, int index);
526  struct singleEntry * findEntryByPath(struct grubConfig * cfg,  struct singleEntry * findEntryByPath(struct grubConfig * cfg,
527       const char * path, const char * prefix,       const char * path, const char * prefix,
528       int * index);       int * index);
 static char * strndup(char * from, int len);  
529  static int readFile(int fd, char ** bufPtr);  static int readFile(int fd, char ** bufPtr);
530  static void lineInit(struct singleLine * line);  static void lineInit(struct singleLine * line);
531    struct singleLine * lineDup(struct singleLine * line);
532  static void lineFree(struct singleLine * line);  static void lineFree(struct singleLine * line);
533  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
534       struct configFileInfo * cfi);       struct configFileInfo * cfi);
535  static int getNextLine(char ** bufPtr, struct singleLine * line,  static int getNextLine(char ** bufPtr, struct singleLine * line,
536         struct configFileInfo * cfi);         struct configFileInfo * cfi);
537  static char * getRootSpecifier(char * str);  static char * getRootSpecifier(char * str);
538    static void requote(struct singleLine *line, struct configFileInfo * cfi);
539  static char * strndup(char * from, int len) {  static void insertElement(struct singleLine * line,
540      char * to;    const char * item, int insertHere,
541      struct configFileInfo * cfi);
542      to = malloc(len + 1);  static void removeElement(struct singleLine * line, int removeHere);
543      strncpy(to, from, len);  static struct keywordTypes * getKeywordByType(enum lineType_e type,
544      to[len] = '\0';        struct configFileInfo * cfi);
545    static enum lineType_e getTypeByKeyword(char * keyword,
546      return to;   struct configFileInfo * cfi);
547  }  static struct singleLine * getLineByType(enum lineType_e type,
548     struct singleLine * line);
549    static int checkForExtLinux(struct grubConfig * config);
550    struct singleLine * addLineTmpl(struct singleEntry * entry,
551                                    struct singleLine * tmplLine,
552                                    struct singleLine * prevLine,
553                                    const char * val,
554     struct configFileInfo * cfi);
555    struct singleLine *  addLine(struct singleEntry * entry,
556                                 struct configFileInfo * cfi,
557                                 enum lineType_e type, char * defaultIndent,
558                                 const char * val);
559    
560  static char * sdupprintf(const char *format, ...)  static char * sdupprintf(const char *format, ...)
561  #ifdef __GNUC__  #ifdef __GNUC__
# Line 313  static char * sdupprintf(const char *for Line 590  static char * sdupprintf(const char *for
590      return buf;      return buf;
591  }  }
592    
593    static enum lineType_e preferredLineType(enum lineType_e type,
594     struct configFileInfo *cfi) {
595        if (isEfi && cfi == &grub2ConfigType) {
596     switch (type) {
597     case LT_KERNEL:
598        return LT_KERNEL_EFI;
599     case LT_INITRD:
600        return LT_INITRD_EFI;
601     default:
602        return type;
603     }
604        }
605        return type;
606    }
607    
608    static struct keywordTypes * getKeywordByType(enum lineType_e type,
609          struct configFileInfo * cfi) {
610        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
611     if (kw->type == type)
612        return kw;
613        }
614        return NULL;
615    }
616    
617    static char *getKeyByType(enum lineType_e type, struct configFileInfo * cfi) {
618        struct keywordTypes *kt = getKeywordByType(type, cfi);
619        if (kt)
620     return kt->key;
621        return "unknown";
622    }
623    
624    static char * getpathbyspec(char *device) {
625        if (!blkid)
626            blkid_get_cache(&blkid, NULL);
627    
628        return blkid_get_devname(blkid, device, NULL);
629    }
630    
631    static char * getuuidbydev(char *device) {
632        if (!blkid)
633     blkid_get_cache(&blkid, NULL);
634    
635        return blkid_get_tag_value(blkid, "UUID", device);
636    }
637    
638    static enum lineType_e getTypeByKeyword(char * keyword,
639     struct configFileInfo * cfi) {
640        for (struct keywordTypes *kw = cfi->keywords; kw->key; kw++) {
641     if (cfi->caseInsensitive) {
642        if (!strcasecmp(keyword, kw->key))
643                    return kw->type;
644     } else {
645        if (!strcmp(keyword, kw->key))
646            return kw->type;
647     }
648        }
649        return LT_UNKNOWN;
650    }
651    
652    static struct singleLine * getLineByType(enum lineType_e type,
653     struct singleLine * line) {
654        dbgPrintf("getLineByType(%d): ", type);
655        for (; line; line = line->next) {
656     dbgPrintf("%d:%s ", line->type,
657      line->numElements ? line->elements[0].item : "(empty)");
658     if (line->type & type) break;
659        }
660        dbgPrintf(line ? "\n" : " (failed)\n");
661        return line;
662    }
663    
664  static int isBracketedTitle(struct singleLine * line) {  static int isBracketedTitle(struct singleLine * line) {
665      if ((*line->elements[0].item == '[') && (line->numElements == 1)) {      if (line->numElements == 1 && *line->elements[0].item == '[') {
666          int len = strlen(line->elements[0].item);          int len = strlen(line->elements[0].item);
667          if (*(line->elements[0].item + len - 1) == ']') {          if (*(line->elements[0].item + len - 1) == ']') {
668              /* FIXME: this is a hack... */              /* FIXME: this is a hack... */
# Line 326  static int isBracketedTitle(struct singl Line 674  static int isBracketedTitle(struct singl
674      return 0;      return 0;
675  }  }
676    
677  /* figure out if this is a entry separator */  static int isEntryStart(struct singleLine * line,
 static int isEntrySeparator(struct singleLine * line,  
678                              struct configFileInfo * cfi) {                              struct configFileInfo * cfi) {
679      if (line->type == LT_WHITESPACE)      return line->type == cfi->entryStart || line->type == LT_OTHER ||
680   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;  
681  }  }
682    
683  /* extract the title from within brackets (for zipl) */  /* extract the title from within brackets (for zipl) */
# Line 389  static void lineInit(struct singleLine * Line 728  static void lineInit(struct singleLine *
728      line->next = NULL;      line->next = NULL;
729  }  }
730    
731  static void lineFree(struct singleLine * line) {  struct singleLine * lineDup(struct singleLine * line) {
732      int i;      struct singleLine * newLine = malloc(sizeof(*newLine));
733    
734        newLine->indent = strdup(line->indent);
735        newLine->next = NULL;
736        newLine->type = line->type;
737        newLine->numElements = line->numElements;
738        newLine->elements = malloc(sizeof(*newLine->elements) *
739           newLine->numElements);
740    
741        for (int i = 0; i < newLine->numElements; i++) {
742     newLine->elements[i].indent = strdup(line->elements[i].indent);
743     newLine->elements[i].item = strdup(line->elements[i].item);
744        }
745    
746        return newLine;
747    }
748    
749    static void lineFree(struct singleLine * line) {
750      if (line->indent) free(line->indent);      if (line->indent) free(line->indent);
751    
752      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
753   free(line->elements[i].item);   free(line->elements[i].item);
754   free(line->elements[i].indent);   free(line->elements[i].indent);
755      }      }
# Line 405  static void lineFree(struct singleLine * Line 760  static void lineFree(struct singleLine *
760    
761  static int lineWrite(FILE * out, struct singleLine * line,  static int lineWrite(FILE * out, struct singleLine * line,
762       struct configFileInfo * cfi) {       struct configFileInfo * cfi) {
     int i;  
   
763      if (fprintf(out, "%s", line->indent) == -1) return -1;      if (fprintf(out, "%s", line->indent) == -1) return -1;
764    
765      for (i = 0; i < line->numElements; i++) {      for (int i = 0; i < line->numElements; i++) {
766     /* Need to handle this, because we strip the quotes from
767     * menuentry when read it. */
768     if (line->type == LT_MENUENTRY && i == 1) {
769        if(!isquote(*line->elements[i].item))
770     fprintf(out, "\'%s\'", line->elements[i].item);
771        else
772     fprintf(out, "%s", line->elements[i].item);
773        fprintf(out, "%s", line->elements[i].indent);
774    
775        continue;
776     }
777    
778   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)   if (i == 1 && line->type == LT_KERNELARGS && cfi->argsInQuotes)
779      if (fputc('"', out) == EOF) return -1;      if (fputc('"', out) == EOF) return -1;
780    
781   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;   if (fprintf(out, "%s", line->elements[i].item) == -1) return -1;
782   if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;   if (i < line->numElements - 1)
783        if (fprintf(out, "%s", line->elements[i].indent) == -1) return -1;
784      }      }
785    
786      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)      if (line->type == LT_KERNELARGS && cfi->argsInQuotes)
# Line 433  static int getNextLine(char ** bufPtr, s Line 799  static int getNextLine(char ** bufPtr, s
799      char * chptr;      char * chptr;
800      int elementsAlloced = 0;      int elementsAlloced = 0;
801      struct lineElement * element;      struct lineElement * element;
     struct keywordTypes * keywords = cfi->keywords;  
802      int first = 1;      int first = 1;
     int i;  
803    
804      lineFree(line);      lineFree(line);
805    
# Line 489  static int getNextLine(char ** bufPtr, s Line 853  static int getNextLine(char ** bufPtr, s
853      if (!line->numElements)      if (!line->numElements)
854   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
855      else {      else {
856   for (i = 0; keywords[i].key; i++)   line->type = getTypeByKeyword(line->elements[0].item, cfi);
857      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;  
               
858              /* zipl does [title] instead of something reasonable like all              /* zipl does [title] instead of something reasonable like all
859               * the other boot loaders.  kind of ugly */               * the other boot loaders.  kind of ugly */
860              if (cfi->titleBracketed && isBracketedTitle(line)) {              if (cfi->titleBracketed && isBracketedTitle(line)) {
# Line 510  static int getNextLine(char ** bufPtr, s Line 868  static int getNextLine(char ** bufPtr, s
868      if (*line->elements[0].item == '#') {      if (*line->elements[0].item == '#') {
869   char * fullLine;   char * fullLine;
870   int len;   int len;
  int i;  
871    
872   len = strlen(line->indent);   len = strlen(line->indent);
873   for (i = 0; i < line->numElements; i++)   for (int i = 0; i < line->numElements; i++)
874      len += strlen(line->elements[i].item) +      len += strlen(line->elements[i].item) +
875     strlen(line->elements[i].indent);     strlen(line->elements[i].indent);
876    
# Line 522  static int getNextLine(char ** bufPtr, s Line 879  static int getNextLine(char ** bufPtr, s
879   free(line->indent);   free(line->indent);
880   line->indent = fullLine;   line->indent = fullLine;
881    
882   for (i = 0; i < line->numElements; i++) {   for (int i = 0; i < line->numElements; i++) {
883      strcat(fullLine, line->elements[i].item);      strcat(fullLine, line->elements[i].item);
884      strcat(fullLine, line->elements[i].indent);      strcat(fullLine, line->elements[i].indent);
885      free(line->elements[i].item);      free(line->elements[i].item);
# Line 532  static int getNextLine(char ** bufPtr, s Line 889  static int getNextLine(char ** bufPtr, s
889   line->type = LT_WHITESPACE;   line->type = LT_WHITESPACE;
890   line->numElements = 0;   line->numElements = 0;
891      }      }
892     } else {
893     struct keywordTypes *kw;
894    
895     kw = getKeywordByType(line->type, cfi);
896    
897     /* space isn't the only separator, we need to split
898     * elements up more
899     */
900     if (!isspace(kw->separatorChar)) {
901        char indent[2] = "";
902        indent[0] = kw->separatorChar;
903        for (int i = 1; i < line->numElements; i++) {
904     char *p;
905     int numNewElements;
906    
907     numNewElements = 0;
908     p = line->elements[i].item;
909     while (*p != '\0') {
910     if (*p == kw->separatorChar)
911     numNewElements++;
912     p++;
913     }
914     if (line->numElements + numNewElements >= elementsAlloced) {
915     elementsAlloced += numNewElements + 5;
916     line->elements = realloc(line->elements,
917        sizeof(*line->elements) * elementsAlloced);
918     }
919    
920     for (int j = line->numElements; j > i; j--) {
921     line->elements[j + numNewElements] = line->elements[j];
922     }
923     line->numElements += numNewElements;
924    
925     p = line->elements[i].item;
926     while (*p != '\0') {
927    
928     while (*p != kw->separatorChar && *p != '\0') p++;
929     if (*p == '\0') {
930     break;
931     }
932    
933     line->elements[i + 1].indent = line->elements[i].indent;
934     line->elements[i].indent = strdup(indent);
935     *p++ = '\0';
936     i++;
937     line->elements[i].item = strdup(p);
938     }
939        }
940     }
941   }   }
942      }      }
943    
# Line 549  static struct grubConfig * readConfig(co Line 955  static struct grubConfig * readConfig(co
955      struct singleLine * last = NULL, * line, * defaultLine = NULL;      struct singleLine * last = NULL, * line, * defaultLine = NULL;
956      char * end;      char * end;
957      struct singleEntry * entry = NULL;      struct singleEntry * entry = NULL;
958      int i, len;      int len;
959      char * buf;      char * buf;
960    
961      if (!strcmp(inName, "-")) {      if (!strcmp(inName, "-")) {
# Line 595  static struct grubConfig * readConfig(co Line 1001  static struct grubConfig * readConfig(co
1001      cfg->secondaryIndent = strdup(line->indent);      cfg->secondaryIndent = strdup(line->indent);
1002   }   }
1003    
1004   if (isEntrySeparator(line, cfi)) {   if (isEntryStart(line, cfi) || (cfg->entries && !sawEntry)) {
1005      sawEntry = 1;      sawEntry = 1;
1006      if (!entry) {      if (!entry) {
1007   cfg->entries = malloc(sizeof(*entry));   cfg->entries = malloc(sizeof(*entry));
# Line 611  static struct grubConfig * readConfig(co Line 1017  static struct grubConfig * readConfig(co
1017      entry->next = NULL;      entry->next = NULL;
1018   }   }
1019    
1020   if (line->type == LT_DEFAULT && line->numElements == 2) {   if (line->type == LT_SET_VARIABLE) {
1021        dbgPrintf("found 'set' command (%d elements): ", line->numElements);
1022        dbgPrintf("%s", line->indent);
1023        for (int i = 0; i < line->numElements; i++)
1024     dbgPrintf("\"%s\"%s", line->elements[i].item, line->elements[i].indent);
1025        dbgPrintf("\n");
1026        struct keywordTypes *kwType = getKeywordByType(LT_DEFAULT, cfi);
1027        if (kwType && line->numElements == 3 &&
1028        !strcmp(line->elements[1].item, kwType->key)) {
1029     dbgPrintf("Line sets default config\n");
1030     cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1031     defaultLine = line;
1032        }
1033     } else if (line->type == LT_DEFAULT && line->numElements == 2) {
1034      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;      cfg->flags &= ~GRUB_CONFIG_NO_DEFAULT;
1035      defaultLine = line;      defaultLine = line;
1036    
1037            } else if (iskernel(line->type)) {
1038        /* if by some freak chance this is multiboot and the "module"
1039         * lines came earlier in the template, make sure to use LT_HYPER
1040         * instead of LT_KERNEL now
1041         */
1042        if (entry->multiboot)
1043     line->type = LT_HYPER;
1044    
1045          } else if (line->type == LT_MBMODULE) {          } else if (line->type == LT_MBMODULE) {
1046        /* go back and fix the LT_KERNEL line to indicate LT_HYPER
1047         * instead, now that we know this is a multiboot entry.
1048         * This only applies to grub, but that's the only place we
1049         * should find LT_MBMODULE lines anyway.
1050         */
1051        for (struct singleLine *l = entry->lines; l; l = l->next) {
1052     if (l->type == LT_HYPER)
1053        break;
1054     else if (iskernel(l->type)) {
1055        l->type = LT_HYPER;
1056        break;
1057     }
1058        }
1059              entry->multiboot = 1;              entry->multiboot = 1;
1060    
1061     } else if (line->type == LT_HYPER) {
1062        entry->multiboot = 1;
1063    
1064   } else if (line->type == LT_FALLBACK && line->numElements == 2) {   } else if (line->type == LT_FALLBACK && line->numElements == 2) {
1065      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);      cfg->fallbackImage = strtol(line->elements[1].item, &end, 10);
1066      if (*end) cfg->fallbackImage = -1;      if (*end) cfg->fallbackImage = -1;
1067    
1068   } else if (line->type == LT_TITLE && line->numElements > 1) {   } else if (line->type == LT_TITLE && line->numElements > 1) {
1069      /* make the title a single argument (undoing our parsing) */      /* make the title a single argument (undoing our parsing) */
1070      len = 0;      len = 0;
1071      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1072   len += strlen(line->elements[i].item);   len += strlen(line->elements[i].item);
1073   len += strlen(line->elements[i].indent);   len += strlen(line->elements[i].indent);
1074      }      }
1075      buf = malloc(len + 1);      buf = malloc(len + 1);
1076      *buf = '\0';      *buf = '\0';
1077    
1078      for (i = 1; i < line->numElements; i++) {      for (int i = 1; i < line->numElements; i++) {
1079   strcat(buf, line->elements[i].item);   strcat(buf, line->elements[i].item);
1080   free(line->elements[i].item);   free(line->elements[i].item);
1081    
# Line 643  static struct grubConfig * readConfig(co Line 1089  static struct grubConfig * readConfig(co
1089      line->elements[line->numElements - 1].indent;      line->elements[line->numElements - 1].indent;
1090      line->elements[1].item = buf;      line->elements[1].item = buf;
1091      line->numElements = 2;      line->numElements = 2;
1092     } else if (line->type == LT_MENUENTRY && line->numElements > 3) {
1093        /* let --remove-kernel="TITLE=what" work */
1094        len = 0;
1095        char *extras;
1096        char *title;
1097    
1098        for (int i = 1; i < line->numElements; i++) {
1099     len += strlen(line->elements[i].item);
1100     len += strlen(line->elements[i].indent);
1101        }
1102        buf = malloc(len + 1);
1103        *buf = '\0';
1104    
1105        /* allocate mem for extra flags. */
1106        extras = malloc(len + 1);
1107        *extras = '\0';
1108    
1109        /* get title. */
1110        for (int i = 0; i < line->numElements; i++) {
1111     if (!strcmp(line->elements[i].item, "menuentry"))
1112        continue;
1113     if (isquote(*line->elements[i].item))
1114        title = line->elements[i].item + 1;
1115     else
1116        title = line->elements[i].item;
1117    
1118     len = strlen(title);
1119            if (isquote(title[len-1])) {
1120        strncat(buf, title,len-1);
1121        break;
1122     } else {
1123        strcat(buf, title);
1124        strcat(buf, line->elements[i].indent);
1125     }
1126        }
1127    
1128        /* get extras */
1129        int count = 0;
1130        for (int i = 0; i < line->numElements; i++) {
1131     if (count >= 2) {
1132        strcat(extras, line->elements[i].item);
1133        strcat(extras, line->elements[i].indent);
1134     }
1135    
1136     if (!strcmp(line->elements[i].item, "menuentry"))
1137        continue;
1138    
1139     /* count ' or ", there should be two in menuentry line. */
1140     if (isquote(*line->elements[i].item))
1141        count++;
1142    
1143     len = strlen(line->elements[i].item);
1144    
1145     if (isquote(line->elements[i].item[len -1]))
1146        count++;
1147    
1148     /* ok, we get the final ' or ", others are extras. */
1149                }
1150        line->elements[1].indent =
1151     line->elements[line->numElements - 2].indent;
1152        line->elements[1].item = buf;
1153        line->elements[2].indent =
1154     line->elements[line->numElements - 2].indent;
1155        line->elements[2].item = extras;
1156        line->numElements = 3;
1157   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {   } else if (line->type == LT_KERNELARGS && cfi->argsInQuotes) {
1158      /* Strip off any " which may be present; they'll be put back      /* Strip off any " which may be present; they'll be put back
1159         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 1162  static struct grubConfig * readConfig(co
1162      if (line->numElements >= 2) {      if (line->numElements >= 2) {
1163   int last, len;   int last, len;
1164    
1165   if (*line->elements[1].item == '"')   if (isquote(*line->elements[1].item))
1166      memcpy(line->elements[1].item, line->elements[1].item + 1,      memmove(line->elements[1].item, line->elements[1].item + 1,
1167     strlen(line->elements[1].item + 1) + 1);      strlen(line->elements[1].item + 1) + 1);
1168    
1169   last = line->numElements - 1;   last = line->numElements - 1;
1170   len = strlen(line->elements[last].item) - 1;   len = strlen(line->elements[last].item) - 1;
1171   if (line->elements[last].item[len] == '"')   if (isquote(line->elements[last].item[len]))
1172      line->elements[last].item[len] = '\0';      line->elements[last].item[len] = '\0';
1173      }      }
   
1174   }   }
1175    
1176   /* 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 1190  static struct grubConfig * readConfig(co
1190   movedLine = 1;   movedLine = 1;
1191   continue; /* without setting 'last' */   continue; /* without setting 'last' */
1192   }   }
1193    
1194   /* If a second line of whitespace happens after a generic option   /* If a second line of whitespace happens after a generic option
1195     which was moved, drop it. */     which was moved, drop it. */
1196   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 1206  static struct grubConfig * readConfig(co
1206   entry->lines = line;   entry->lines = line;
1207      else      else
1208   last->next = line;   last->next = line;
1209        dbgPrintf("readConfig added %s to %p\n", getKeyByType(line->type, cfi), entry);
1210    
1211        /* we could have seen this outside of an entry... if so, we
1212         * ignore it like any other line we don't grok */
1213        if (line->type == LT_ENTRY_END && sawEntry)
1214     sawEntry = 0;
1215   } else {   } else {
1216      if (!cfg->theLines)      if (!cfg->theLines)
1217   cfg->theLines = line;   cfg->theLines = line;
1218      else {      else
1219   last->next = line;   last->next = line;
1220      }      dbgPrintf("readConfig added %s to cfg\n", getKeyByType(line->type, cfi));
1221   }   }
1222    
1223   last = line;   last = line;
# Line 708  static struct grubConfig * readConfig(co Line 1225  static struct grubConfig * readConfig(co
1225    
1226      free(incoming);      free(incoming);
1227    
1228        dbgPrintf("defaultLine is %s\n", defaultLine ? "set" : "unset");
1229      if (defaultLine) {      if (defaultLine) {
1230   if (cfi->defaultSupportSaved &&          if (defaultLine->numElements > 2 &&
1231        cfi->defaultSupportSaved &&
1232        !strncmp(defaultLine->elements[2].item,"\"${saved_entry}\"", 16)) {
1233        cfg->defaultImage = DEFAULT_SAVED_GRUB2;
1234     } else if (cfi->defaultIsVariable) {
1235        char *value = defaultLine->elements[2].item;
1236        while (*value && (*value == '"' || *value == '\'' ||
1237        *value == ' ' || *value == '\t'))
1238     value++;
1239        cfg->defaultImage = strtol(value, &end, 10);
1240        while (*end && (*end == '"' || *end == '\'' ||
1241        *end == ' ' || *end == '\t'))
1242     end++;
1243        if (*end) cfg->defaultImage = -1;
1244     } else if (cfi->defaultSupportSaved &&
1245   !strncmp(defaultLine->elements[1].item, "saved", 5)) {   !strncmp(defaultLine->elements[1].item, "saved", 5)) {
1246      cfg->defaultImage = DEFAULT_SAVED;      cfg->defaultImage = DEFAULT_SAVED;
1247   } else if (cfi->defaultIsIndex) {   } else if (cfi->defaultIsIndex) {
1248      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);      cfg->defaultImage = strtol(defaultLine->elements[1].item, &end, 10);
1249      if (*end) cfg->defaultImage = -1;      if (*end) cfg->defaultImage = -1;
1250   } else if (defaultLine->numElements >= 2) {   } else if (defaultLine->numElements >= 2) {
1251      i = 0;      int i = 0;
1252      while ((entry = findEntryByIndex(cfg, i))) {      while ((entry = findEntryByIndex(cfg, i))) {
1253   for (line = entry->lines; line; line = line->next)   for (line = entry->lines; line; line = line->next)
1254      if (line->type == LT_TITLE) break;      if (line->type == LT_TITLE) break;
# Line 730  static struct grubConfig * readConfig(co Line 1262  static struct grubConfig * readConfig(co
1262                                  extractTitle(line))) break;                                  extractTitle(line))) break;
1263                  }                  }
1264   i++;   i++;
1265     entry = NULL;
1266      }      }
1267    
1268      if (entry) cfg->defaultImage = i;      if (entry){
1269            cfg->defaultImage = i;
1270        }else{
1271            cfg->defaultImage = -1;
1272        }
1273   }   }
1274        } else {
1275            cfg->defaultImage = 0;
1276      }      }
1277    
1278      return cfg;      return cfg;
# Line 749  static void writeDefault(FILE * out, cha Line 1288  static void writeDefault(FILE * out, cha
1288    
1289      if (cfg->defaultImage == DEFAULT_SAVED)      if (cfg->defaultImage == DEFAULT_SAVED)
1290   fprintf(out, "%sdefault%ssaved\n", indent, separator);   fprintf(out, "%sdefault%ssaved\n", indent, separator);
1291        else if (cfg->defaultImage == DEFAULT_SAVED_GRUB2)
1292     fprintf(out, "%sset default=\"${saved_entry}\"\n", indent);
1293      else if (cfg->defaultImage > -1) {      else if (cfg->defaultImage > -1) {
1294   if (cfg->cfi->defaultIsIndex) {   if (cfg->cfi->defaultIsIndex) {
1295      fprintf(out, "%sdefault%s%d\n", indent, separator,      if (cfg->cfi->defaultIsVariable) {
1296      cfg->defaultImage);          fprintf(out, "%sset default=\"%d\"\n", indent,
1297     cfg->defaultImage);
1298        } else {
1299     fprintf(out, "%sdefault%s%d\n", indent, separator,
1300     cfg->defaultImage);
1301        }
1302   } else {   } else {
1303      int image = cfg->defaultImage;      int image = cfg->defaultImage;
1304    
# Line 769  static void writeDefault(FILE * out, cha Line 1315  static void writeDefault(FILE * out, cha
1315    
1316      if (!entry) return;      if (!entry) return;
1317    
1318      line = entry->lines;      line = getLineByType(LT_TITLE, entry->lines);
     while (line && line->type != LT_TITLE) line = line->next;  
1319    
1320      if (line && line->numElements >= 2)      if (line && line->numElements >= 2)
1321   fprintf(out, "%sdefault%s%s\n", indent, separator,   fprintf(out, "%sdefault%s%s\n", indent, separator,
# Line 804  static int writeConfig(struct grubConfig Line 1349  static int writeConfig(struct grubConfig
1349      int rc;      int rc;
1350    
1351      /* most likely the symlink is relative, so change our      /* most likely the symlink is relative, so change our
1352         directory to / */         directory to the dir of the symlink */
1353      rc = chdir("/");      char *dir = strdupa(outName);
1354        rc = chdir(dirname(dir));
1355      do {      do {
1356   buf = alloca(len + 1);   buf = alloca(len + 1);
1357   rc = readlink(outName, buf, len);   rc = readlink(basename(outName), buf, len);
1358   if (rc == len) len += 256;   if (rc == len) len += 256;
1359      } while (rc == len);      } while (rc == len);
1360            
# Line 843  static int writeConfig(struct grubConfig Line 1389  static int writeConfig(struct grubConfig
1389      }      }
1390    
1391      line = cfg->theLines;      line = cfg->theLines;
1392        struct keywordTypes *defaultKw = getKeywordByType(LT_DEFAULT, cfg->cfi);
1393      while (line) {      while (line) {
1394   if (line->type == LT_DEFAULT) {          if (line->type == LT_SET_VARIABLE && defaultKw &&
1395     line->numElements == 3 &&
1396     !strcmp(line->elements[1].item, defaultKw->key)) {
1397        writeDefault(out, line->indent, line->elements[0].indent, cfg);
1398        needs &= ~MAIN_DEFAULT;
1399     } else if (line->type == LT_DEFAULT) {
1400      writeDefault(out, line->indent, line->elements[0].indent, cfg);      writeDefault(out, line->indent, line->elements[0].indent, cfg);
1401      needs &= ~MAIN_DEFAULT;      needs &= ~MAIN_DEFAULT;
1402   } else if (line->type == LT_FALLBACK) {   } else if (line->type == LT_FALLBACK) {
# Line 912  static int numEntries(struct grubConfig Line 1464  static int numEntries(struct grubConfig
1464      return i;      return i;
1465  }  }
1466    
1467  int suitableImage(struct singleEntry * entry, const char * bootPrefix,  static char *findDiskForRoot()
1468    int skipRemoved, int flags) {  {
1469      struct singleLine * line;      int fd;
1470      char * fullName;      char buf[65536];
1471      int i;      char *devname;
1472      struct stat sb, sb2;      char *chptr;
1473      char * dev;      int rc;
     char * end;  
     char * rootspec;  
1474    
1475      line = entry->lines;      if ((fd = open(_PATH_MOUNTED, O_RDONLY)) < 0) {
1476      while (line && line->type != LT_KERNEL) line = line->next;          fprintf(stderr, "grubby: failed to open %s: %s\n",
1477                        _PATH_MOUNTED, strerror(errno));
1478      if (!line) return 0;          return NULL;
1479      if (skipRemoved && entry->skip) return 0;      }
1480      if (line->numElements < 2) return 0;  
1481        rc = read(fd, buf, sizeof(buf) - 1);
1482        if (rc <= 0) {
1483            fprintf(stderr, "grubby: failed to read %s: %s\n",
1484                    _PATH_MOUNTED, strerror(errno));
1485            close(fd);
1486            return NULL;
1487        }
1488        close(fd);
1489        buf[rc] = '\0';
1490        chptr = buf;
1491    
1492      if (flags & GRUBBY_BADIMAGE_OKAY) return 1;      char *foundanswer = NULL;
1493    
1494      fullName = alloca(strlen(bootPrefix) +      while (chptr && chptr != buf+rc) {
1495        strlen(line->elements[1].item) + 1);          devname = chptr;
     rootspec = getRootSpecifier(line->elements[1].item);  
     sprintf(fullName, "%s%s", bootPrefix,  
             line->elements[1].item + ((rootspec != NULL) ?  
                                       strlen(rootspec) : 0));  
     if (access(fullName, R_OK)) return 0;  
1496    
1497      for (i = 2; i < line->numElements; i++)          /*
1498   if (!strncasecmp(line->elements[i].item, "root=", 5)) break;           * The first column of a mtab entry is the device, but if the entry is a
1499      if (i < line->numElements) {           * special device it won't start with /, so move on to the next line.
1500   dev = line->elements[i].item + 5;           */
1501      } else {          if (*devname != '/') {
1502   /* look for a lilo style LT_ROOT line */              chptr = strchr(chptr, '\n');
1503   line = entry->lines;              if (chptr)
1504   while (line && line->type != LT_ROOT) line = line->next;                  chptr++;
1505                continue;
1506            }
1507    
1508   if (line && line->numElements >= 2) {          /* Seek to the next space */
1509      dev = line->elements[1].item;          chptr = strchr(chptr, ' ');
1510   } else {          if (!chptr) {
1511              int type;              fprintf(stderr, "grubby: error parsing %s: %s\n",
1512      /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS */                      _PATH_MOUNTED, strerror(errno));
1513      line = entry->lines;              return NULL;
1514            }
1515    
1516              type = ((entry->multiboot) ? LT_MBMODULE : LT_KERNELARGS);          /*
1517             * The second column of a mtab entry is the mount point, we are looking
1518             * for '/' obviously.
1519             */
1520            if (*(++chptr) == '/' && *(++chptr) == ' ') {
1521                /* remember the last / entry in mtab */
1522               foundanswer = devname;
1523            }
1524    
1525      while (line && line->type != type) line = line->next;          /* Next line */
1526            chptr = strchr(chptr, '\n');
1527            if (chptr)
1528                chptr++;
1529        }
1530    
1531              /* failed to find one */      /* Return the last / entry found */
1532              if (!line) return 0;      if (foundanswer) {
1533            chptr = strchr(foundanswer, ' ');
1534            *chptr = '\0';
1535            return strdup(foundanswer);
1536        }
1537    
1538      for (i = 1; i < line->numElements; i++)      return NULL;
1539          if (!strncasecmp(line->elements[i].item, "root=", 5)) break;  }
1540      if (i < line->numElements)  
1541          dev = line->elements[i].item + 5;  void printEntry(struct singleEntry * entry, FILE *f) {
1542      else {      int i;
1543   /* it failed too...  can't find root= */      struct singleLine * line;
1544          return 0;  
1545              }      for (line = entry->lines; line; line = line->next) {
1546     log_message(f, "DBG: %s", line->indent);
1547     for (i = 0; i < line->numElements; i++) {
1548        /* Need to handle this, because we strip the quotes from
1549         * menuentry when read it. */
1550        if (line->type == LT_MENUENTRY && i == 1) {
1551     if(!isquote(*line->elements[i].item))
1552        log_message(f, "\'%s\'", line->elements[i].item);
1553     else
1554        log_message(f, "%s", line->elements[i].item);
1555     log_message(f, "%s", line->elements[i].indent);
1556    
1557     continue;
1558        }
1559        
1560        log_message(f, "%s%s",
1561        line->elements[i].item, line->elements[i].indent);
1562   }   }
1563     log_message(f, "\n");
1564      }      }
1565    }
1566    
1567      if (!strncmp(dev, "LABEL=", 6)) {  void notSuitablePrintf(struct singleEntry * entry, int okay, const char *fmt, ...)
1568   dev += 6;  {
1569        static int once;
1570   /* check which device has this label */      va_list argp, argq;
1571   dev = get_spec_by_volume_label(dev, &i, &i);  
1572   if (!dev) return 0;      va_start(argp, fmt);
1573    
1574        va_copy(argq, argp);
1575        if (!once) {
1576     log_time(NULL);
1577     log_message(NULL, "command line: %s\n", saved_command_line);
1578      }      }
1579        log_message(NULL, "DBG: Image entry %s: ", okay ? "succeeded" : "failed");
1580        log_vmessage(NULL, fmt, argq);
1581    
1582        printEntry(entry, NULL);
1583        va_end(argq);
1584    
1585      if (*dev == '/') {      if (!debug) {
1586   if (stat(dev, &sb))   once = 1;
1587      return 0;       va_end(argp);
1588      } else {   return;
  sb.st_rdev = strtol(dev, &end, 16);  
  if (*end) return 0;  
1589      }      }
     stat("/", &sb2);  
1590    
1591      if (sb.st_rdev != sb2.st_dev) return 0;      if (okay) {
1592     va_end(argp);
1593     return;
1594        }
1595    
1596      return 1;      if (!once)
1597     log_message(stderr, "DBG: command line: %s\n", saved_command_line);
1598        once = 1;
1599        fprintf(stderr, "DBG: Image entry failed: ");
1600        vfprintf(stderr, fmt, argp);
1601        printEntry(entry, stderr);
1602        va_end(argp);
1603  }  }
1604    
1605  /* returns the first match on or after the one pointed to by index (if index  #define beginswith(s, c) ((s) && (s)[0] == (c))
1606    
1607    static int endswith(const char *s, char c)
1608    {
1609     int slen;
1610    
1611     if (!s || !s[0])
1612     return 0;
1613     slen = strlen(s) - 1;
1614    
1615     return s[slen] == c;
1616    }
1617    
1618    int suitableImage(struct singleEntry * entry, const char * bootPrefix,
1619      int skipRemoved, int flags) {
1620        struct singleLine * line;
1621        char * fullName;
1622        int i;
1623        char * dev;
1624        char * rootspec;
1625        char * rootdev;
1626    
1627        if (skipRemoved && entry->skip) {
1628     notSuitablePrintf(entry, 0, "marked to skip\n");
1629     return 0;
1630        }
1631    
1632        line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
1633        if (!line) {
1634     notSuitablePrintf(entry, 0, "no line found\n");
1635     return 0;
1636        }
1637        if (line->numElements < 2) {
1638     notSuitablePrintf(entry, 0, "line has only %d elements\n",
1639        line->numElements);
1640     return 0;
1641        }
1642    
1643        if (flags & GRUBBY_BADIMAGE_OKAY) {
1644        notSuitablePrintf(entry, 1, "\n");
1645        return 1;
1646        }
1647    
1648        fullName = alloca(strlen(bootPrefix) +
1649          strlen(line->elements[1].item) + 1);
1650        rootspec = getRootSpecifier(line->elements[1].item);
1651        int rootspec_offset = rootspec ? strlen(rootspec) : 0;
1652        int hasslash = endswith(bootPrefix, '/') ||
1653         beginswith(line->elements[1].item + rootspec_offset, '/');
1654        sprintf(fullName, "%s%s%s", bootPrefix, hasslash ? "" : "/",
1655                line->elements[1].item + rootspec_offset);
1656        if (access(fullName, R_OK)) {
1657     notSuitablePrintf(entry, 0, "access to %s failed\n", fullName);
1658     return 0;
1659        }
1660        for (i = 2; i < line->numElements; i++)
1661     if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1662        if (i < line->numElements) {
1663     dev = line->elements[i].item + 5;
1664        } else {
1665     /* look for a lilo style LT_ROOT line */
1666     line = getLineByType(LT_ROOT, entry->lines);
1667    
1668     if (line && line->numElements >= 2) {
1669        dev = line->elements[1].item;
1670     } else {
1671        /* didn't succeed in finding a LT_ROOT, let's try LT_KERNELARGS.
1672         * grub+multiboot uses LT_MBMODULE for the args, so check that too.
1673         */
1674        line = getLineByType(LT_KERNELARGS|LT_MBMODULE, entry->lines);
1675    
1676                /* failed to find one */
1677                if (!line) {
1678     notSuitablePrintf(entry, 0, "no line found\n");
1679     return 0;
1680                }
1681    
1682        for (i = 1; i < line->numElements; i++)
1683            if (!strncasecmp(line->elements[i].item, "root=", 5)) break;
1684        if (i < line->numElements)
1685            dev = line->elements[i].item + 5;
1686        else {
1687     notSuitablePrintf(entry, 0, "no root= entry found\n");
1688     /* it failed too...  can't find root= */
1689            return 0;
1690                }
1691     }
1692        }
1693    
1694        dev = getpathbyspec(dev);
1695        if (!getpathbyspec(dev)) {
1696            notSuitablePrintf(entry, 0, "can't find blkid entry for %s\n", dev);
1697            return 0;
1698        } else
1699     dev = getpathbyspec(dev);
1700    
1701        rootdev = findDiskForRoot();
1702        if (!rootdev) {
1703            notSuitablePrintf(entry, 0, "can't find root device\n");
1704     return 0;
1705        }
1706    
1707        if (!getuuidbydev(rootdev) || !getuuidbydev(dev)) {
1708            notSuitablePrintf(entry, 0, "uuid missing: rootdev %s, dev %s\n",
1709     getuuidbydev(rootdev), getuuidbydev(dev));
1710            free(rootdev);
1711            return 0;
1712        }
1713    
1714        if (strcmp(getuuidbydev(rootdev), getuuidbydev(dev))) {
1715            notSuitablePrintf(entry, 0, "uuid mismatch: rootdev %s, dev %s\n",
1716     getuuidbydev(rootdev), getuuidbydev(dev));
1717     free(rootdev);
1718            return 0;
1719        }
1720    
1721        free(rootdev);
1722        notSuitablePrintf(entry, 1, "\n");
1723    
1724        return 1;
1725    }
1726    
1727    /* returns the first match on or after the one pointed to by index (if index
1728     is not NULL) which is not marked as skip */     is not NULL) which is not marked as skip */
1729  struct singleEntry * findEntryByPath(struct grubConfig * config,  struct singleEntry * findEntryByPath(struct grubConfig * config,
1730       const char * kernel, const char * prefix,       const char * kernel, const char * prefix,
# Line 1034  struct singleEntry * findEntryByPath(str Line 1763  struct singleEntry * findEntryByPath(str
1763   entry = findEntryByIndex(config, indexVars[i]);   entry = findEntryByIndex(config, indexVars[i]);
1764   if (!entry) return NULL;   if (!entry) return NULL;
1765    
1766   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL)  
     line = line->next;  
   
1767   if (!line) return NULL;   if (!line) return NULL;
1768    
1769   if (index) *index = indexVars[i];   if (index) *index = indexVars[i];
# Line 1075  struct singleEntry * findEntryByPath(str Line 1801  struct singleEntry * findEntryByPath(str
1801    
1802   if (!strncmp(kernel, "TITLE=", 6)) {   if (!strncmp(kernel, "TITLE=", 6)) {
1803      prefix = "";      prefix = "";
1804      checkType = LT_TITLE;      checkType = LT_TITLE|LT_MENUENTRY;
1805      kernel += 6;      kernel += 6;
1806   }   }
1807    
1808   while ((entry = findEntryByIndex(config, i))) {   for (entry = findEntryByIndex(config, i); entry; entry = entry->next, i++) {
1809      line = entry->lines;      if (entry->skip) continue;
     while (line && line->type != checkType) line=line->next;  
1810    
1811        dbgPrintf("findEntryByPath looking for %d %s in %p\n", checkType, kernel, entry);
1812    
1813      if (line && line->numElements >= 2 && !entry->skip) {      /* check all the lines matching checkType */
1814                  rootspec = getRootSpecifier(line->elements[1].item);      for (line = entry->lines; line; line = line->next) {
1815          if (!strcmp(line->elements[1].item  +   enum lineType_e ct = checkType;
1816                              ((rootspec != NULL) ? strlen(rootspec) : 0),   if (entry->multiboot && checkType == LT_KERNEL)
1817                              kernel + strlen(prefix)))      ct = LT_KERNEL|LT_KERNEL_EFI|LT_MBMODULE|LT_HYPER;
1818                      break;   else if (checkType & LT_KERNEL)
1819              }      ct = checkType | LT_KERNEL_EFI;
1820                 line = getLineByType(ct, line);
1821              /* have to check multiboot lines too */   if (!line)
1822              if (entry->multiboot) {      break;  /* not found in this entry */
1823                  while (line && line->type != LT_MBMODULE) line = line->next;  
1824                  if (line && line->numElements >= 2 && !entry->skip) {   if (line && line->type != LT_MENUENTRY &&
1825                      rootspec = getRootSpecifier(line->elements[1].item);   line->numElements >= 2) {
1826                      if (!strcmp(line->elements[1].item  +      rootspec = getRootSpecifier(line->elements[1].item);
1827                                  ((rootspec != NULL) ? strlen(rootspec) : 0),      if (!strcmp(line->elements[1].item +
1828                                  kernel + strlen(prefix)))   ((rootspec != NULL) ? strlen(rootspec) : 0),
1829                          break;   kernel + strlen(prefix)))
1830                  }   break;
1831              }   }
1832     if(line->type == LT_MENUENTRY &&
1833     !strcmp(line->elements[1].item, kernel))
1834        break;
1835        }
1836    
1837      i++;      /* make sure this entry has a kernel identifier; this skips
1838         * non-Linux boot entries (could find netbsd etc, though, which is
1839         * unfortunate)
1840         */
1841        if (line && getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines))
1842     break; /* found 'im! */
1843   }   }
1844    
1845   if (index) *index = i;   if (index) *index = i;
1846      }      }
1847    
     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);  
     }  
   
1848      return entry;      return entry;
1849  }  }
1850    
# Line 1200  void markRemovedImage(struct grubConfig Line 1923  void markRemovedImage(struct grubConfig
1923        const char * prefix) {        const char * prefix) {
1924      struct singleEntry * entry;      struct singleEntry * entry;
1925    
1926      if (!image) return;      if (!image)
1927     return;
1928    
1929        /* check and see if we're removing the default image */
1930        if (isdigit(*image)) {
1931     entry = findEntryByPath(cfg, image, prefix, NULL);
1932     if(entry)
1933        entry->skip = 1;
1934     return;
1935        }
1936    
1937      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))      while ((entry = findEntryByPath(cfg, image, prefix, NULL)))
1938   entry->skip = 1;   entry->skip = 1;
# Line 1208  void markRemovedImage(struct grubConfig Line 1940  void markRemovedImage(struct grubConfig
1940    
1941  void setDefaultImage(struct grubConfig * config, int hasNew,  void setDefaultImage(struct grubConfig * config, int hasNew,
1942       const char * defaultKernelPath, int newIsDefault,       const char * defaultKernelPath, int newIsDefault,
1943       const char * prefix, int flags) {       const char * prefix, int flags, int index) {
1944      struct singleEntry * entry, * entry2, * newDefault;      struct singleEntry * entry, * entry2, * newDefault;
1945      int i, j;      int i, j;
1946    
1947      if (newIsDefault) {      if (newIsDefault) {
1948   config->defaultImage = 0;   config->defaultImage = 0;
1949   return;   return;
1950        } else if ((index >= 0) && config->cfi->defaultIsIndex) {
1951     if (findEntryByIndex(config, index))
1952        config->defaultImage = index;
1953     else
1954        config->defaultImage = -1;
1955     return;
1956      } else if (defaultKernelPath) {      } else if (defaultKernelPath) {
1957   i = 0;   i = 0;
1958   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {   if (findEntryByPath(config, defaultKernelPath, prefix, &i)) {
# Line 1227  void setDefaultImage(struct grubConfig * Line 1965  void setDefaultImage(struct grubConfig *
1965    
1966      /* 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
1967         changes */         changes */
1968      if (config->defaultImage == DEFAULT_SAVED)      if ((config->defaultImage == DEFAULT_SAVED) ||
1969     (config->defaultImage == DEFAULT_SAVED_GRUB2))
1970        /* default is set to saved, we don't want to change it */        /* default is set to saved, we don't want to change it */
1971        return;        return;
1972    
# Line 1286  void displayEntry(struct singleEntry * e Line 2025  void displayEntry(struct singleEntry * e
2025      char * root = NULL;      char * root = NULL;
2026      int i;      int i;
2027    
     line = entry->lines;  
     while (line && line->type != LT_KERNEL) line = line->next;  
   
2028      printf("index=%d\n", index);      printf("index=%d\n", index);
2029    
2030      printf("kernel=%s\n", line->elements[1].item);      line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
2031        if (!line) {
2032            printf("non linux entry\n");
2033            return;
2034        }
2035    
2036        if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2037     printf("kernel=%s\n", line->elements[1].item);
2038        else
2039     printf("kernel=%s%s\n", prefix, line->elements[1].item);
2040    
2041      if (line->numElements >= 3) {      if (line->numElements >= 3) {
2042   printf("args=\"");   printf("args=\"");
# Line 1308  void displayEntry(struct singleEntry * e Line 2053  void displayEntry(struct singleEntry * e
2053   }   }
2054   printf("\"\n");   printf("\"\n");
2055      } else {      } else {
2056   line = entry->lines;   line = getLineByType(LT_KERNELARGS, entry->lines);
  while (line && line->type != LT_KERNELARGS) line=line->next;  
   
2057   if (line) {   if (line) {
2058      char * s;      char * s;
2059    
# Line 1334  void displayEntry(struct singleEntry * e Line 2077  void displayEntry(struct singleEntry * e
2077      }      }
2078    
2079      if (!root) {      if (!root) {
2080   line = entry->lines;   line = getLineByType(LT_ROOT, entry->lines);
  while (line && line->type != LT_ROOT) line = line->next;  
   
2081   if (line && line->numElements >= 2)   if (line && line->numElements >= 2)
2082      root=line->elements[1].item;      root=line->elements[1].item;
2083      }      }
# Line 1351  void displayEntry(struct singleEntry * e Line 2092  void displayEntry(struct singleEntry * e
2092   printf("root=%s\n", s);   printf("root=%s\n", s);
2093      }      }
2094    
2095      line = entry->lines;      line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
     while (line && line->type != LT_INITRD) line = line->next;  
2096    
2097      if (line && line->numElements >= 2) {      if (line && line->numElements >= 2) {
2098   printf("initrd=%s", prefix);   if (!strncmp(prefix, line->elements[1].item, strlen(prefix)))
2099        printf("initrd=");
2100     else
2101        printf("initrd=%s", prefix);
2102    
2103   for (i = 1; i < line->numElements; i++)   for (i = 1; i < line->numElements; i++)
2104      printf("%s%s", line->elements[i].item, line->elements[i].indent);      printf("%s%s", line->elements[i].item, line->elements[i].indent);
2105   printf("\n");   printf("\n");
2106      }      }
2107    
2108        line = getLineByType(LT_TITLE, entry->lines);
2109        if (line) {
2110     printf("title=%s\n", line->elements[1].item);
2111        } else {
2112     char * title;
2113     line = getLineByType(LT_MENUENTRY, entry->lines);
2114     title = grub2ExtractTitle(line);
2115     if (title)
2116        printf("title=%s\n", title);
2117        }
2118    }
2119    
2120    int isSuseSystem(void) {
2121        const char * path;
2122        const static char default_path[] = "/etc/SuSE-release";
2123    
2124        if ((path = getenv("GRUBBY_SUSE_RELEASE")) == NULL)
2125     path = default_path;
2126    
2127        if (!access(path, R_OK))
2128     return 1;
2129        return 0;
2130    }
2131    
2132    int isSuseGrubConf(const char * path) {
2133        FILE * grubConf;
2134        char * line = NULL;
2135        size_t len = 0, res = 0;
2136    
2137        grubConf = fopen(path, "r");
2138        if (!grubConf) {
2139            dbgPrintf("Could not open SuSE configuration file '%s'\n", path);
2140     return 0;
2141        }
2142    
2143        while ((res = getline(&line, &len, grubConf)) != -1) {
2144     if (!strncmp(line, "setup", 5)) {
2145        fclose(grubConf);
2146        free(line);
2147        return 1;
2148     }
2149        }
2150    
2151        dbgPrintf("SuSE configuration file '%s' does not appear to be valid\n",
2152          path);
2153    
2154        fclose(grubConf);
2155        free(line);
2156        return 0;
2157    }
2158    
2159    int suseGrubConfGetLba(const char * path, int * lbaPtr) {
2160        FILE * grubConf;
2161        char * line = NULL;
2162        size_t res = 0, len = 0;
2163    
2164        if (!path) return 1;
2165        if (!lbaPtr) return 1;
2166    
2167        grubConf = fopen(path, "r");
2168        if (!grubConf) return 1;
2169    
2170        while ((res = getline(&line, &len, grubConf)) != -1) {
2171     if (line[res - 1] == '\n')
2172        line[res - 1] = '\0';
2173     else if (len > res)
2174        line[res] = '\0';
2175     else {
2176        line = realloc(line, res + 1);
2177        line[res] = '\0';
2178     }
2179    
2180     if (!strncmp(line, "setup", 5)) {
2181        if (strstr(line, "--force-lba")) {
2182            *lbaPtr = 1;
2183        } else {
2184            *lbaPtr = 0;
2185        }
2186        dbgPrintf("lba: %i\n", *lbaPtr);
2187        break;
2188     }
2189        }
2190    
2191        free(line);
2192        fclose(grubConf);
2193        return 0;
2194    }
2195    
2196    int suseGrubConfGetInstallDevice(const char * path, char ** devicePtr) {
2197        FILE * grubConf;
2198        char * line = NULL;
2199        size_t res = 0, len = 0;
2200        char * lastParamPtr = NULL;
2201        char * secLastParamPtr = NULL;
2202        char installDeviceNumber = '\0';
2203        char * bounds = NULL;
2204    
2205        if (!path) return 1;
2206        if (!devicePtr) return 1;
2207    
2208        grubConf = fopen(path, "r");
2209        if (!grubConf) return 1;
2210    
2211        while ((res = getline(&line, &len, grubConf)) != -1) {
2212     if (strncmp(line, "setup", 5))
2213        continue;
2214    
2215     if (line[res - 1] == '\n')
2216        line[res - 1] = '\0';
2217     else if (len > res)
2218        line[res] = '\0';
2219     else {
2220        line = realloc(line, res + 1);
2221        line[res] = '\0';
2222     }
2223    
2224     lastParamPtr = bounds = line + res;
2225    
2226     /* Last parameter in grub may be an optional IMAGE_DEVICE */
2227     while (!isspace(*lastParamPtr))
2228        lastParamPtr--;
2229     lastParamPtr++;
2230    
2231     secLastParamPtr = lastParamPtr - 2;
2232     dbgPrintf("lastParamPtr: %s\n", lastParamPtr);
2233    
2234     if (lastParamPtr + 3 > bounds) {
2235        dbgPrintf("lastParamPtr going over boundary");
2236        fclose(grubConf);
2237        free(line);
2238        return 1;
2239     }
2240     if (!strncmp(lastParamPtr, "(hd", 3))
2241        lastParamPtr += 3;
2242     dbgPrintf("lastParamPtr: %c\n", *lastParamPtr);
2243    
2244     /*
2245     * Second last parameter will decide wether last parameter is
2246     * an IMAGE_DEVICE or INSTALL_DEVICE
2247     */
2248     while (!isspace(*secLastParamPtr))
2249        secLastParamPtr--;
2250     secLastParamPtr++;
2251    
2252     if (secLastParamPtr + 3 > bounds) {
2253        dbgPrintf("secLastParamPtr going over boundary");
2254        fclose(grubConf);
2255        free(line);
2256        return 1;
2257     }
2258     dbgPrintf("secLastParamPtr: %s\n", secLastParamPtr);
2259     if (!strncmp(secLastParamPtr, "(hd", 3)) {
2260        secLastParamPtr += 3;
2261        dbgPrintf("secLastParamPtr: %c\n", *secLastParamPtr);
2262        installDeviceNumber = *secLastParamPtr;
2263     } else {
2264        installDeviceNumber = *lastParamPtr;
2265     }
2266    
2267     *devicePtr = malloc(6);
2268     snprintf(*devicePtr, 6, "(hd%c)", installDeviceNumber);
2269     dbgPrintf("installDeviceNumber: %c\n", installDeviceNumber);
2270     fclose(grubConf);
2271     free(line);
2272     return 0;
2273        }
2274    
2275        free(line);
2276        fclose(grubConf);
2277        return 1;
2278    }
2279    
2280    int grubGetBootFromDeviceMap(const char * device,
2281         char ** bootPtr) {
2282        FILE * deviceMap;
2283        char * line = NULL;
2284        size_t res = 0, len = 0;
2285        char * devicePtr;
2286        char * bounds = NULL;
2287        const char * path;
2288        const static char default_path[] = "/boot/grub/device.map";
2289    
2290        if (!device) return 1;
2291        if (!bootPtr) return 1;
2292    
2293        if ((path = getenv("GRUBBY_GRUB_DEVICE_MAP")) == NULL)
2294     path = default_path;
2295    
2296        dbgPrintf("opening grub device.map file from: %s\n", path);
2297        deviceMap = fopen(path, "r");
2298        if (!deviceMap)
2299     return 1;
2300    
2301        while ((res = getline(&line, &len, deviceMap)) != -1) {
2302            if (!strncmp(line, "#", 1))
2303        continue;
2304    
2305     if (line[res - 1] == '\n')
2306        line[res - 1] = '\0';
2307     else if (len > res)
2308        line[res] = '\0';
2309     else {
2310        line = realloc(line, res + 1);
2311        line[res] = '\0';
2312     }
2313    
2314     devicePtr = line;
2315     bounds = line + res;
2316    
2317     while ((isspace(*line) && ((devicePtr + 1) <= bounds)))
2318        devicePtr++;
2319     dbgPrintf("device: %s\n", devicePtr);
2320    
2321     if (!strncmp(devicePtr, device, strlen(device))) {
2322        devicePtr += strlen(device);
2323        while (isspace(*devicePtr) && ((devicePtr + 1) <= bounds))
2324            devicePtr++;
2325    
2326        *bootPtr = strdup(devicePtr);
2327        break;
2328     }
2329        }
2330    
2331        free(line);
2332        fclose(deviceMap);
2333        return 0;
2334    }
2335    
2336    int suseGrubConfGetBoot(const char * path, char ** bootPtr) {
2337        char * grubDevice;
2338    
2339        if (suseGrubConfGetInstallDevice(path, &grubDevice))
2340     dbgPrintf("error looking for grub installation device\n");
2341        else
2342     dbgPrintf("grubby installation device: %s\n", grubDevice);
2343    
2344        if (grubGetBootFromDeviceMap(grubDevice, bootPtr))
2345     dbgPrintf("error looking for grub boot device\n");
2346        else
2347     dbgPrintf("grubby boot device: %s\n", *bootPtr);
2348    
2349        free(grubDevice);
2350        return 0;
2351    }
2352    
2353    int parseSuseGrubConf(int * lbaPtr, char ** bootPtr) {
2354        /*
2355         * This SuSE grub configuration file at this location is not your average
2356         * grub configuration file, but instead the grub commands used to setup
2357         * grub on that system.
2358         */
2359        const char * path;
2360        const static char default_path[] = "/etc/grub.conf";
2361    
2362        if ((path = getenv("GRUBBY_SUSE_GRUB_CONF")) == NULL)
2363     path = default_path;
2364    
2365        if (!isSuseGrubConf(path)) return 1;
2366    
2367        if (lbaPtr) {
2368            *lbaPtr = 0;
2369            if (suseGrubConfGetLba(path, lbaPtr))
2370                return 1;
2371        }
2372    
2373        if (bootPtr) {
2374            *bootPtr = NULL;
2375            suseGrubConfGetBoot(path, bootPtr);
2376        }
2377    
2378        return 0;
2379  }  }
2380    
2381  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {  int parseSysconfigGrub(int * lbaPtr, char ** bootPtr) {
# Line 1369  int parseSysconfigGrub(int * lbaPtr, cha Line 2385  int parseSysconfigGrub(int * lbaPtr, cha
2385      char * start;      char * start;
2386      char * param;      char * param;
2387    
2388      in = fopen("/etc/sysconfig/grub", "r");      in = fopen("/etc/conf.d/grub", "r");
2389      if (!in) return 1;      if (!in) return 1;
2390    
2391      if (lbaPtr) *lbaPtr = 0;      if (lbaPtr) *lbaPtr = 0;
# Line 1410  int parseSysconfigGrub(int * lbaPtr, cha Line 2426  int parseSysconfigGrub(int * lbaPtr, cha
2426  }  }
2427    
2428  void dumpSysconfigGrub(void) {  void dumpSysconfigGrub(void) {
2429      char * boot;      char * boot = NULL;
2430      int lba;      int lba;
2431    
2432      if (!parseSysconfigGrub(&lba, &boot)) {      if (isSuseSystem()) {
2433   if (lba) printf("lba\n");          if (parseSuseGrubConf(&lba, &boot)) {
2434   if (boot) printf("boot=%s\n", boot);      free(boot);
2435        return;
2436     }
2437        } else {
2438            if (parseSysconfigGrub(&lba, &boot)) {
2439        free(boot);
2440        return;
2441     }
2442        }
2443    
2444        if (lba) printf("lba\n");
2445        if (boot) {
2446     printf("boot=%s\n", boot);
2447     free(boot);
2448      }      }
2449  }  }
2450    
# Line 1431  int displayInfo(struct grubConfig * conf Line 2460  int displayInfo(struct grubConfig * conf
2460   return 1;   return 1;
2461      }      }
2462    
2463      /* 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
2464         be a better way */         be a better way */
2465      if (config->cfi == &grubConfigType) {      if (config->cfi == &grubConfigType) {
2466   dumpSysconfigGrub();   dumpSysconfigGrub();
2467      } else {      } else {
2468   line = config->theLines;   line = getLineByType(LT_BOOT, config->theLines);
  while (line && line->type != LT_BOOT) line = line->next;  
2469   if (line && line->numElements >= 1) {   if (line && line->numElements >= 1) {
2470      printf("boot=%s\n", line->elements[1].item);      printf("boot=%s\n", line->elements[1].item);
2471   }   }
2472    
2473   line = config->theLines;   line = getLineByType(LT_LBA, config->theLines);
  while (line && line->type != LT_LBA) line = line->next;  
2474   if (line) printf("lba\n");   if (line) printf("lba\n");
2475      }      }
2476    
# Line 1458  int displayInfo(struct grubConfig * conf Line 2485  int displayInfo(struct grubConfig * conf
2485      return 0;      return 0;
2486  }  }
2487    
2488    struct singleLine * addLineTmpl(struct singleEntry * entry,
2489     struct singleLine * tmplLine,
2490     struct singleLine * prevLine,
2491     const char * val,
2492     struct configFileInfo * cfi)
2493    {
2494        struct singleLine * newLine = lineDup(tmplLine);
2495    
2496        if (isEfi && cfi == &grub2ConfigType) {
2497     enum lineType_e old = newLine->type;
2498     newLine->type = preferredLineType(newLine->type, cfi);
2499     if (old != newLine->type)
2500        newLine->elements[0].item = getKeyByType(newLine->type, cfi);
2501        }
2502    
2503        if (val) {
2504     /* override the inherited value with our own.
2505     * This is a little weak because it only applies to elements[1]
2506     */
2507     if (newLine->numElements > 1)
2508        removeElement(newLine, 1);
2509     insertElement(newLine, val, 1, cfi);
2510    
2511     /* but try to keep the rootspec from the template... sigh */
2512     if (tmplLine->type & (LT_HYPER|LT_KERNEL|LT_MBMODULE|LT_INITRD|LT_KERNEL_EFI|LT_INITRD_EFI)) {
2513        char * rootspec = getRootSpecifier(tmplLine->elements[1].item);
2514        if (rootspec != NULL) {
2515     free(newLine->elements[1].item);
2516     newLine->elements[1].item =
2517        sdupprintf("%s%s", rootspec, val);
2518        }
2519     }
2520        }
2521    
2522        dbgPrintf("addLineTmpl(%s)\n", newLine->numElements ?
2523          newLine->elements[0].item : "");
2524    
2525        if (!entry->lines) {
2526     /* first one on the list */
2527     entry->lines = newLine;
2528        } else if (prevLine) {
2529     /* add after prevLine */
2530     newLine->next = prevLine->next;
2531     prevLine->next = newLine;
2532        }
2533    
2534        return newLine;
2535    }
2536    
2537  /* val may be NULL */  /* val may be NULL */
2538  struct singleLine *  addLine(struct singleEntry * entry,  struct singleLine *  addLine(struct singleEntry * entry,
2539       struct configFileInfo * cfi,       struct configFileInfo * cfi,
2540       enum lineType_e type, const char * defaultIndent,       enum lineType_e type, char * defaultIndent,
2541       char * val) {       const char * val) {
2542      struct singleLine * line, * prev;      struct singleLine * line, * prev;
2543      int i;      struct keywordTypes * kw;
2544        struct singleLine tmpl;
2545    
2546      for (i = 0; cfi->keywords[i].key; i++)      /* NB: This function shouldn't allocate items on the heap, rather on the
2547   if (cfi->keywords[i].type == type) break;       * stack since it calls addLineTmpl which will make copies.
2548      if (type != LT_TITLE || !cfi->titleBracketed)       */
2549          if (!cfi->keywords[i].key) abort();      if (type == LT_TITLE && cfi->titleBracketed) {
2550     /* we're doing a bracketed title (zipl) */
2551     tmpl.type = type;
2552     tmpl.numElements = 1;
2553     tmpl.elements = alloca(sizeof(*tmpl.elements));
2554     tmpl.elements[0].item = alloca(strlen(val)+3);
2555     sprintf(tmpl.elements[0].item, "[%s]", val);
2556     tmpl.elements[0].indent = "";
2557     val = NULL;
2558        } else if (type == LT_MENUENTRY) {
2559     char *lineend = "--class gnu-linux --class gnu --class os {";
2560     if (!val) {
2561        fprintf(stderr, "Line type LT_MENUENTRY requires a value\n");
2562        abort();
2563     }
2564     kw = getKeywordByType(type, cfi);
2565     if (!kw) {
2566        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2567        abort();
2568     }
2569     tmpl.indent = "";
2570     tmpl.type = type;
2571     tmpl.numElements = 3;
2572     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2573     tmpl.elements[0].item = kw->key;
2574     tmpl.elements[0].indent = alloca(2);
2575     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2576     tmpl.elements[1].item = (char *)val;
2577     tmpl.elements[1].indent = alloca(2);
2578     sprintf(tmpl.elements[1].indent, "%c", kw->nextChar);
2579     tmpl.elements[2].item = alloca(strlen(lineend)+1);
2580     strcpy(tmpl.elements[2].item, lineend);
2581     tmpl.elements[2].indent = "";
2582        } else {
2583     kw = getKeywordByType(type, cfi);
2584     if (!kw) {
2585        fprintf(stderr, "Looking up keyword for unknown type %d\n", type);
2586        abort();
2587     }
2588     tmpl.type = type;
2589     tmpl.numElements = val ? 2 : 1;
2590     tmpl.elements = alloca(sizeof(*tmpl.elements) * tmpl.numElements);
2591     tmpl.elements[0].item = kw->key;
2592     tmpl.elements[0].indent = alloca(2);
2593     sprintf(tmpl.elements[0].indent, "%c", kw->nextChar);
2594     if (val) {
2595        tmpl.elements[1].item = (char *)val;
2596        tmpl.elements[1].indent = "";
2597     }
2598        }
2599    
2600      /* 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
2601         to insert after. Note that comments are considered empty lines, which         to insert after. Note that comments are considered empty lines, which
2602         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
2603         first line, we use defaultIndent (the first line is normally indented         first line, we use defaultIndent (the first line is normally indented
2604         differently from the rest) */         differently from the rest) */
2605      if (entry->lines) {      for (line = entry->lines, prev = NULL; line; line = line->next) {
2606   line = entry->lines;   if (line->numElements) prev = line;
2607   prev = NULL;   /* fall back on the last line if prev isn't otherwise set */
2608   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;  
2609      }      }
2610    
2611      if (type != LT_TITLE || !cfi->titleBracketed) {      struct singleLine *menuEntry;
2612          line->type = type;      menuEntry = getLineByType(LT_MENUENTRY, entry->lines);
2613          line->numElements = val ? 2 : 1;      if (tmpl.type == LT_ENTRY_END) {
2614          line->elements = malloc(sizeof(*line->elements) * line->numElements);   if (menuEntry)
2615          line->elements[0].item = strdup(cfi->keywords[i].key);      tmpl.indent = menuEntry->indent;
2616          line->elements[0].indent = malloc(2);   else
2617          line->elements[0].indent[0] = cfi->keywords[i].nextChar;      tmpl.indent = defaultIndent ?: "";
2618          line->elements[0].indent[1] = '\0';      } else if (tmpl.type != LT_MENUENTRY) {
2619             if (menuEntry)
2620          if (val) {      tmpl.indent = "\t";
2621              line->elements[1].item = val;   else if (prev == entry->lines)
2622              line->elements[1].indent = strdup("");      tmpl.indent = defaultIndent ?: "";
2623          }   else
2624      } 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("");  
2625      }      }
2626    
2627      return line;      return addLineTmpl(entry, &tmpl, prev, val, cfi);
2628  }  }
2629    
2630  void removeLine(struct singleEntry * entry, struct singleLine * line) {  void removeLine(struct singleEntry * entry, struct singleLine * line) {
# Line 1553  void removeLine(struct singleEntry * ent Line 2649  void removeLine(struct singleEntry * ent
2649      free(line);      free(line);
2650  }  }
2651    
2652    static void requote(struct singleLine *tmplLine, struct configFileInfo * cfi)
2653    {
2654        struct singleLine newLine = {
2655     .indent = tmplLine->indent,
2656     .type = tmplLine->type,
2657     .next = tmplLine->next,
2658        };
2659        int firstQuotedItem = -1;
2660        int quoteLen = 0;
2661        int j;
2662        int element = 0;
2663        char *c;
2664    
2665        c = malloc(strlen(tmplLine->elements[0].item) + 1);
2666        strcpy(c, tmplLine->elements[0].item);
2667        insertElement(&newLine, c, element++, cfi);
2668        free(c);
2669        c = NULL;
2670    
2671        for (j = 1; j < tmplLine->numElements; j++) {
2672     if (firstQuotedItem == -1) {
2673        quoteLen += strlen(tmplLine->elements[j].item);
2674        
2675        if (isquote(tmplLine->elements[j].item[0])) {
2676     firstQuotedItem = j;
2677            quoteLen += strlen(tmplLine->elements[j].indent);
2678        } else {
2679     c = malloc(quoteLen + 1);
2680     strcpy(c, tmplLine->elements[j].item);
2681     insertElement(&newLine, c, element++, cfi);
2682     free(c);
2683     quoteLen = 0;
2684        }
2685     } else {
2686        int itemlen = strlen(tmplLine->elements[j].item);
2687        quoteLen += itemlen;
2688        quoteLen += strlen(tmplLine->elements[j].indent);
2689        
2690        if (isquote(tmplLine->elements[j].item[itemlen - 1])) {
2691     c = malloc(quoteLen + 1);
2692     c[0] = '\0';
2693     for (int i = firstQuotedItem; i < j+1; i++) {
2694        strcat(c, tmplLine->elements[i].item);
2695        strcat(c, tmplLine->elements[i].indent);
2696     }
2697     insertElement(&newLine, c, element++, cfi);
2698     free(c);
2699    
2700     firstQuotedItem = -1;
2701     quoteLen = 0;
2702        }
2703     }
2704        }
2705        while (tmplLine->numElements)
2706     removeElement(tmplLine, 0);
2707        if (tmplLine->elements)
2708     free(tmplLine->elements);
2709    
2710        tmplLine->numElements = newLine.numElements;
2711        tmplLine->elements = newLine.elements;
2712    }
2713    
2714    static void insertElement(struct singleLine * line,
2715      const char * item, int insertHere,
2716      struct configFileInfo * cfi)
2717    {
2718        struct keywordTypes * kw;
2719        char indent[2] = "";
2720    
2721        /* sanity check */
2722        if (insertHere > line->numElements) {
2723     dbgPrintf("insertElement() adjusting insertHere from %d to %d\n",
2724      insertHere, line->numElements);
2725     insertHere = line->numElements;
2726        }
2727    
2728        line->elements = realloc(line->elements, (line->numElements + 1) *
2729         sizeof(*line->elements));
2730        memmove(&line->elements[insertHere+1],
2731        &line->elements[insertHere],
2732        (line->numElements - insertHere) *
2733        sizeof(*line->elements));
2734        line->elements[insertHere].item = strdup(item);
2735    
2736        kw = getKeywordByType(line->type, cfi);
2737    
2738        if (line->numElements == 0) {
2739     indent[0] = '\0';
2740        } else if (insertHere == 0) {
2741     indent[0] = kw->nextChar;
2742        } else if (kw->separatorChar != '\0') {
2743     indent[0] = kw->separatorChar;
2744        } else {
2745     indent[0] = ' ';
2746        }
2747    
2748        if (insertHere > 0 && line->elements[insertHere-1].indent[0] == '\0') {
2749     /* move the end-of-line forward */
2750     line->elements[insertHere].indent =
2751        line->elements[insertHere-1].indent;
2752     line->elements[insertHere-1].indent = strdup(indent);
2753        } else {
2754     line->elements[insertHere].indent = strdup(indent);
2755        }
2756    
2757        line->numElements++;
2758    
2759        dbgPrintf("insertElement(%s, '%s%s', %d)\n",
2760          line->elements[0].item,
2761          line->elements[insertHere].item,
2762          line->elements[insertHere].indent,
2763          insertHere);
2764    }
2765    
2766    static void removeElement(struct singleLine * line, int removeHere) {
2767        int i;
2768    
2769        /* sanity check */
2770        if (removeHere >= line->numElements) return;
2771    
2772        dbgPrintf("removeElement(%s, %d:%s)\n", line->elements[0].item,
2773          removeHere, line->elements[removeHere].item);
2774    
2775        free(line->elements[removeHere].item);
2776    
2777        if (removeHere > 1) {
2778     /* previous argument gets this argument's post-indentation */
2779     free(line->elements[removeHere-1].indent);
2780     line->elements[removeHere-1].indent =
2781        line->elements[removeHere].indent;
2782        } else {
2783     free(line->elements[removeHere].indent);
2784        }
2785    
2786        /* now collapse the array, but don't bother to realloc smaller */
2787        for (i = removeHere; i < line->numElements - 1; i++)
2788     line->elements[i] = line->elements[i + 1];
2789    
2790        line->numElements--;
2791    }
2792    
2793  int argMatch(const char * one, const char * two) {  int argMatch(const char * one, const char * two) {
2794      char * first, * second;      char * first, * second;
2795      char * chptr;      char * chptr;
# Line 1575  int updateActualImage(struct grubConfig Line 2812  int updateActualImage(struct grubConfig
2812      struct singleEntry * entry;      struct singleEntry * entry;
2813      struct singleLine * line, * rootLine;      struct singleLine * line, * rootLine;
2814      int index = 0;      int index = 0;
2815      int i, j, k;      int i, k;
2816      const char ** newArgs, ** oldArgs;      const char ** newArgs, ** oldArgs;
2817      const char ** arg;      const char ** arg;
2818      const char * chptr;      int useKernelArgs, useRoot;
     int useKernelArgs = 0;  
     int useRoot = 0;  
2819      int firstElement;      int firstElement;
2820      int *usedElements, *usedArgs;      int *usedElements;
2821        int doreplace;
2822    
2823      if (!image) return 0;      if (!image) return 0;
2824    
# Line 1609  int updateActualImage(struct grubConfig Line 2845  int updateActualImage(struct grubConfig
2845   }   }
2846      }      }
2847    
     for (i = 0; cfg->cfi->keywords[i].key; i++)  
  if (cfg->cfi->keywords[i].type == LT_KERNELARGS) break;  
2848    
2849      if (cfg->cfi->keywords[i].key)      useKernelArgs = (getKeywordByType(LT_KERNELARGS, cfg->cfi)
2850   useKernelArgs = 1;       && (!multibootArgs || cfg->cfi->mbConcatArgs));
2851    
2852      for (i = 0; cfg->cfi->keywords[i].key; i++)      useRoot = (getKeywordByType(LT_ROOT, cfg->cfi)
2853   if (cfg->cfi->keywords[i].type == LT_ROOT) break;         && !multibootArgs);
2854    
2855      if (cfg->cfi->keywords[i].key)      for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
  useRoot = 1;  
2856    
2857      k = 0;   if (multibootArgs && !entry->multiboot)
2858      for (arg = newArgs; *arg; arg++)      continue;
2859          k++;  
2860      usedArgs = calloc(k, sizeof(int));   /* Determine where to put the args.  If this config supports
2861     * LT_KERNELARGS, use that.  Otherwise use
2862     * LT_HYPER/LT_KERNEL/LT_MBMODULE lines.
2863     */
2864     if (useKernelArgs) {
2865        line = getLineByType(LT_KERNELARGS, entry->lines);
2866        if (!line) {
2867     /* no LT_KERNELARGS, need to add it */
2868     line = addLine(entry, cfg->cfi, LT_KERNELARGS,
2869           cfg->secondaryIndent, NULL);
2870        }
2871        firstElement = 1;
2872    
2873      while ((entry = findEntryByPath(cfg, image, prefix, &index))) {   } else if (multibootArgs) {
2874   index++;      line = getLineByType(LT_HYPER, entry->lines);
2875        if (!line) {
2876     /* a multiboot entry without LT_HYPER? */
2877     continue;
2878        }
2879        firstElement = 2;
2880    
2881   line = entry->lines;   } else {
2882   while (line && line->type != LT_KERNEL) line = line->next;      line = getLineByType(LT_KERNEL|LT_MBMODULE|LT_KERNEL_EFI, entry->lines);
2883   if (!line) continue;      if (!line) {
2884   firstElement = 2;   /* no LT_KERNEL or LT_MBMODULE in this entry? */
2885     continue;
2886          if (entry->multiboot && !multibootArgs) {      }
2887              /* 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;  
2888   }   }
2889    
2890   if (!line && useKernelArgs) {   /* handle the elilo case which does:
2891      /* no append in there, need to add it */   *   append="hypervisor args -- kernel args"
2892      line = addLine(entry, cfg->cfi, LT_KERNELARGS, NULL, NULL);   */
2893     if (entry->multiboot && cfg->cfi->mbConcatArgs) {
2894        /* this is a multiboot entry, make sure there's
2895         * -- on the args line
2896         */
2897        for (i = firstElement; i < line->numElements; i++) {
2898     if (!strcmp(line->elements[i].item, "--"))
2899        break;
2900        }
2901        if (i == line->numElements) {
2902     /* assume all existing args are kernel args,
2903     * prepend -- to make it official
2904     */
2905     insertElement(line, "--", firstElement, cfg->cfi);
2906     i = firstElement;
2907        }
2908        if (!multibootArgs) {
2909     /* kernel args start after the -- */
2910     firstElement = i + 1;
2911        }
2912     } else if (cfg->cfi->mbConcatArgs) {
2913        /* this is a non-multiboot entry, remove hyper args */
2914        for (i = firstElement; i < line->numElements; i++) {
2915     if (!strcmp(line->elements[i].item, "--"))
2916        break;
2917        }
2918        if (i < line->numElements) {
2919     /* remove args up to -- */
2920     while (strcmp(line->elements[firstElement].item, "--"))
2921        removeElement(line, firstElement);
2922     /* remove -- */
2923     removeElement(line, firstElement);
2924        }
2925   }   }
2926    
2927          usedElements = calloc(line->numElements, sizeof(int));          usedElements = calloc(line->numElements, sizeof(*usedElements));
2928    
2929          k = 0;   for (k = 0, arg = newArgs; *arg; arg++, k++) {
2930   for (arg = newArgs; *arg; arg++) {  
2931              if (usedArgs[k]) {      doreplace = 1;
                 k++;  
                 continue;  
             }  
2932      for (i = firstElement; i < line->numElements; i++) {      for (i = firstElement; i < line->numElements; i++) {
2933     if (multibootArgs && cfg->cfi->mbConcatArgs &&
2934        !strcmp(line->elements[i].item, "--"))
2935     {
2936        /* reached the end of hyper args, insert here */
2937        doreplace = 0;
2938        break;  
2939     }
2940                  if (usedElements[i])                  if (usedElements[i])
2941                      continue;                      continue;
2942   if (!argMatch(line->elements[i].item, *arg)) {   if (!argMatch(line->elements[i].item, *arg)) {
2943                      usedElements[i]=1;                      usedElements[i]=1;
                     usedArgs[k]=1;  
2944      break;      break;
2945                  }                  }
2946              }              }
     chptr = strchr(*arg, '=');  
2947    
2948      if (i < line->numElements) {      if (i < line->numElements && doreplace) {
2949   /* replace */   /* direct replacement */
2950   free(line->elements[i].item);   free(line->elements[i].item);
2951   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("");  
  }  
2952    
2953   free(rootLine->elements[1].item);      } else if (useRoot && !strncmp(*arg, "root=/dev/", 10)) {
2954   rootLine->elements[1].item = strdup(chptr + 1);   /* root= replacement */
2955      } else {   rootLine = getLineByType(LT_ROOT, entry->lines);
2956   /* append */   if (rootLine) {
2957   line->elements = realloc(line->elements,      free(rootLine->elements[1].item);
2958   (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(" ");  
2959   } else {   } else {
2960      /* First thing on this line; treat a bit differently. Note      rootLine = addLine(entry, cfg->cfi, LT_ROOT,
2961         this is only possible if we've added a LT_KERNELARGS         cfg->secondaryIndent, *arg + 5);
        entry */  
     line->elements[line->numElements].indent = strdup("");  
2962   }   }
2963        }
2964    
2965   line->numElements++;      else {
2966     /* insert/append */
2967     insertElement(line, *arg, i, cfg->cfi);
2968     usedElements = realloc(usedElements, line->numElements *
2969           sizeof(*usedElements));
2970     memmove(&usedElements[i + 1], &usedElements[i],
2971     line->numElements - i - 1);
2972     usedElements[i] = 1;
2973    
2974   /* if we updated a root= here even though there is a   /* if we updated a root= here even though there is a
2975     LT_ROOT available we need to remove the LT_ROOT entry     LT_ROOT available we need to remove the LT_ROOT entry
2976     (this will happen if we switch from a device to a label) */     (this will happen if we switch from a device to a label) */
2977   if (useRoot && !strncmp(*arg, "root=", 5)) {   if (useRoot && !strncmp(*arg, "root=", 5)) {
2978      rootLine = entry->lines;      rootLine = getLineByType(LT_ROOT, entry->lines);
2979      while (rootLine && rootLine->type != LT_ROOT)      if (rootLine)
  rootLine = rootLine->next;  
     if (rootLine) {  
2980   removeLine(entry, rootLine);   removeLine(entry, rootLine);
     }  
2981   }   }
2982      }      }
             k++;  
2983   }   }
2984    
2985          free(usedElements);          free(usedElements);
2986    
  /* 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? */  
2987   for (arg = oldArgs; *arg; arg++) {   for (arg = oldArgs; *arg; arg++) {
2988      for (i = firstElement; i < line->numElements; i++)      for (i = firstElement; i < line->numElements; i++) {
2989   if (!argMatch(line->elements[i].item, *arg))   if (multibootArgs && cfg->cfi->mbConcatArgs &&
2990        !strcmp(line->elements[i].item, "--"))
2991        /* reached the end of hyper args, stop here */
2992        break;
2993     if (!argMatch(line->elements[i].item, *arg)) {
2994        removeElement(line, i);
2995      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;  
2996   }   }
2997        }
2998   free(line->elements[i].item);      /* handle removing LT_ROOT line too */
2999        if (useRoot && !strncmp(*arg, "root=", 5)) {
3000   for (j = i + 1; j < line->numElements; j++)   rootLine = getLineByType(LT_ROOT, entry->lines);
3001      line->elements[j - 1] = line->elements[j];   if (rootLine)
3002        removeLine(entry, rootLine);
  line->numElements--;  
3003      }      }
3004   }   }
3005    
# Line 1760  int updateActualImage(struct grubConfig Line 3010  int updateActualImage(struct grubConfig
3010   }   }
3011      }      }
3012    
     free(usedArgs);  
3013      free(newArgs);      free(newArgs);
3014      free(oldArgs);      free(oldArgs);
3015    
# Line 1786  int updateImage(struct grubConfig * cfg, Line 3035  int updateImage(struct grubConfig * cfg,
3035      return rc;      return rc;
3036  }  }
3037    
3038    int updateInitrd(struct grubConfig * cfg, const char * image,
3039                     const char * prefix, const char * initrd) {
3040        struct singleEntry * entry;
3041        struct singleLine * line, * kernelLine, *endLine = NULL;
3042        int index = 0;
3043    
3044        if (!image) return 0;
3045    
3046        for (; (entry = findEntryByPath(cfg, image, prefix, &index)); index++) {
3047            kernelLine = getLineByType(LT_KERNEL|LT_KERNEL_EFI, entry->lines);
3048            if (!kernelLine) continue;
3049    
3050            line = getLineByType(LT_INITRD|LT_INITRD_EFI, entry->lines);
3051            if (line)
3052                removeLine(entry, line);
3053            if (prefix) {
3054                int prefixLen = strlen(prefix);
3055                if (!strncmp(initrd, prefix, prefixLen))
3056                    initrd += prefixLen;
3057            }
3058     endLine = getLineByType(LT_ENTRY_END, entry->lines);
3059     if (endLine)
3060        removeLine(entry, endLine);
3061            line = addLine(entry, cfg->cfi, preferredLineType(LT_INITRD, cfg->cfi),
3062     kernelLine->indent, initrd);
3063            if (!line)
3064        return 1;
3065     if (endLine) {
3066        line = addLine(entry, cfg->cfi, LT_ENTRY_END, "", NULL);
3067                if (!line)
3068     return 1;
3069     }
3070    
3071            break;
3072        }
3073    
3074        return 0;
3075    }
3076    
3077  int checkDeviceBootloader(const char * device, const unsigned char * boot) {  int checkDeviceBootloader(const char * device, const unsigned char * boot) {
3078      int fd;      int fd;
3079      unsigned char bootSect[512];      unsigned char bootSect[512];
# Line 1809  int checkDeviceBootloader(const char * d Line 3097  int checkDeviceBootloader(const char * d
3097      if (memcmp(boot, bootSect, 3))      if (memcmp(boot, bootSect, 3))
3098   return 0;   return 0;
3099    
3100      if (boot[1] == 0xeb) {      if (boot[1] == JMP_SHORT_OPCODE) {
3101   offset = boot[2] + 2;   offset = boot[2] + 2;
3102      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {      } else if (boot[1] == 0xe8 || boot[1] == 0xe9) {
3103   offset = (boot[3] << 8) + boot[2] + 2;   offset = (boot[3] << 8) + boot[2] + 2;
3104      } else if (boot[0] == 0xeb) {      } else if (boot[0] == JMP_SHORT_OPCODE) {
3105   offset = boot[1] + 2;        offset = boot[1] + 2;
3106            /*
3107     * it looks like grub, when copying stage1 into the mbr, patches stage1
3108     * right after the JMP location, replacing other instructions such as
3109     * JMPs for NOOPs. So, relax the check a little bit by skipping those
3110     * different bytes.
3111     */
3112          if ((bootSect[offset + 1] == NOOP_OPCODE)
3113      && (bootSect[offset + 2] == NOOP_OPCODE)) {
3114     offset = offset + 3;
3115          }
3116      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {      } else if (boot[0] == 0xe8 || boot[0] == 0xe9) {
3117   offset = (boot[2] << 8) + boot[1] + 2;   offset = (boot[2] << 8) + boot[1] + 2;
3118      } else {      } else {
# Line 1956  int checkForLilo(struct grubConfig * con Line 3254  int checkForLilo(struct grubConfig * con
3254      return checkDeviceBootloader(line->elements[1].item, boot);      return checkDeviceBootloader(line->elements[1].item, boot);
3255  }  }
3256    
3257    int checkForGrub2(struct grubConfig * config) {
3258        if (!access("/etc/grub.d/", R_OK))
3259     return 2;
3260    
3261        return 1;
3262    }
3263    
3264  int checkForGrub(struct grubConfig * config) {  int checkForGrub(struct grubConfig * config) {
3265      int fd;      int fd;
3266      unsigned char bootSect[512];      unsigned char bootSect[512];
3267      char * boot;      char * boot;
3268        int onSuse = isSuseSystem();
3269    
3270      if (parseSysconfigGrub(NULL, &boot))  
3271   return 0;      if (onSuse) {
3272     if (parseSuseGrubConf(NULL, &boot))
3273        return 0;
3274        } else {
3275     if (parseSysconfigGrub(NULL, &boot))
3276        return 0;
3277        }
3278    
3279      /* assume grub is not installed -- not an error condition */      /* assume grub is not installed -- not an error condition */
3280      if (!boot)      if (!boot)
# Line 1976  int checkForGrub(struct grubConfig * con Line 3288  int checkForGrub(struct grubConfig * con
3288      if (read(fd, bootSect, 512) != 512) {      if (read(fd, bootSect, 512) != 512) {
3289   fprintf(stderr, _("grubby: unable to read %s: %s\n"),   fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3290   "/boot/grub/stage1", strerror(errno));   "/boot/grub/stage1", strerror(errno));
3291     close(fd);
3292     return 1;
3293        }
3294        close(fd);
3295    
3296        /* The more elaborate checks do not work on SuSE. The checks done
3297         * seem to be reasonble (at least for now), so just return success
3298         */
3299        if (onSuse)
3300     return 2;
3301    
3302        return checkDeviceBootloader(boot, bootSect);
3303    }
3304    
3305    int checkForExtLinux(struct grubConfig * config) {
3306        int fd;
3307        unsigned char bootSect[512];
3308        char * boot;
3309        char executable[] = "/boot/extlinux/extlinux";
3310    
3311        printf("entered: checkForExtLinux()\n");
3312    
3313        if (parseSysconfigGrub(NULL, &boot))
3314     return 0;
3315    
3316        /* assume grub is not installed -- not an error condition */
3317        if (!boot)
3318     return 0;
3319    
3320        fd = open(executable, O_RDONLY);
3321        if (fd < 0)
3322     /* this doesn't exist if grub hasn't been installed */
3323     return 0;
3324    
3325        if (read(fd, bootSect, 512) != 512) {
3326     fprintf(stderr, _("grubby: unable to read %s: %s\n"),
3327     executable, strerror(errno));
3328   return 1;   return 1;
3329      }      }
3330      close(fd);      close(fd);
# Line 1983  int checkForGrub(struct grubConfig * con Line 3332  int checkForGrub(struct grubConfig * con
3332      return checkDeviceBootloader(boot, bootSect);      return checkDeviceBootloader(boot, bootSect);
3333  }  }
3334    
3335    int checkForYaboot(struct grubConfig * config) {
3336        /*
3337         * This is a simplistic check that we consider good enough for own puporses
3338         *
3339         * If we were to properly check if yaboot is *installed* we'd need to:
3340         * 1) get the system boot device (LT_BOOT)
3341         * 2) considering it's a raw filesystem, check if the yaboot binary matches
3342         *    the content on the boot device
3343         * 3) if not, copy the binary to a temporary file and run "addnote" on it
3344         * 4) check again if binary and boot device contents match
3345         */
3346        if (!access("/etc/yaboot.conf", R_OK))
3347     return 2;
3348    
3349        return 1;
3350    }
3351    
3352    int checkForElilo(struct grubConfig * config) {
3353        if (!access("/etc/elilo.conf", R_OK))
3354     return 2;
3355    
3356        return 1;
3357    }
3358    
3359  static char * getRootSpecifier(char * str) {  static char * getRootSpecifier(char * str) {
3360      char * idx, * rootspec = NULL;      char * idx, * rootspec = NULL;
3361    
# Line 1994  static char * getRootSpecifier(char * st Line 3367  static char * getRootSpecifier(char * st
3367      return rootspec;      return rootspec;
3368  }  }
3369    
3370    static char * getInitrdVal(struct grubConfig * config,
3371       const char * prefix, struct singleLine *tmplLine,
3372       const char * newKernelInitrd,
3373       const char ** extraInitrds, int extraInitrdCount)
3374    {
3375        char *initrdVal, *end;
3376        int i;
3377        size_t totalSize;
3378        size_t prefixLen;
3379        char separatorChar;
3380    
3381        prefixLen = strlen(prefix);
3382        totalSize = strlen(newKernelInitrd) - prefixLen + 1 /* \0 */;
3383    
3384        for (i = 0; i < extraInitrdCount; i++) {
3385     totalSize += sizeof(separatorChar);
3386     totalSize += strlen(extraInitrds[i]) - prefixLen;
3387        }
3388    
3389        initrdVal = end = malloc(totalSize);
3390    
3391        end = stpcpy (end, newKernelInitrd + prefixLen);
3392    
3393        separatorChar = getKeywordByType(LT_INITRD, config->cfi)->separatorChar;
3394        for (i = 0; i < extraInitrdCount; i++) {
3395     const char *extraInitrd;
3396     int j;
3397    
3398     extraInitrd = extraInitrds[i] + prefixLen;
3399     /* Don't add entries that are already there */
3400     if (tmplLine != NULL) {
3401        for (j = 2; j < tmplLine->numElements; j++)
3402     if (strcmp(extraInitrd, tmplLine->elements[j].item) == 0)
3403        break;
3404    
3405        if (j != tmplLine->numElements)
3406     continue;
3407     }
3408    
3409     *end++ = separatorChar;
3410     end = stpcpy(end, extraInitrd);
3411        }
3412    
3413        return initrdVal;
3414    }
3415    
3416  int addNewKernel(struct grubConfig * config, struct singleEntry * template,  int addNewKernel(struct grubConfig * config, struct singleEntry * template,
3417           const char * prefix,           const char * prefix,
3418   char * newKernelPath, char * newKernelTitle,   const char * newKernelPath, const char * newKernelTitle,
3419   char * newKernelArgs, char * newKernelInitrd,   const char * newKernelArgs, const char * newKernelInitrd,
3420                   char * newMBKernel, char * newMBKernelArgs) {   const char ** extraInitrds, int extraInitrdCount,
3421                     const char * newMBKernel, const char * newMBKernelArgs) {
3422      struct singleEntry * new;      struct singleEntry * new;
3423      struct singleLine * newLine = NULL, * tmplLine = NULL, * lastLine = NULL;      struct singleLine * newLine = NULL, * tmplLine = NULL, * masterLine = NULL;
3424      int needs;      int needs;
     char * indent = NULL;  
     char * rootspec = NULL;  
3425      char * chptr;      char * chptr;
     int i;  
     enum lineType_e type;  
3426    
3427      if (!newKernelPath) return 0;      if (!newKernelPath) return 0;
3428    
# Line 2036  int addNewKernel(struct grubConfig * con Line 3452  int addNewKernel(struct grubConfig * con
3452      config->entries = new;      config->entries = new;
3453    
3454      /* copy/update from the template */      /* copy/update from the template */
3455      needs = KERNEL_KERNEL | KERNEL_INITRD | KERNEL_TITLE;      needs = NEED_KERNEL | NEED_TITLE;
3456        if (newKernelInitrd)
3457     needs |= NEED_INITRD;
3458      if (newMBKernel) {      if (newMBKernel) {
3459          needs |= KERNEL_MB;          needs |= NEED_MB;
3460          new->multiboot = 1;          new->multiboot = 1;
3461      }      }
3462    
3463      if (template) {      if (template) {
3464   for (tmplLine = template->lines; tmplLine; tmplLine = tmplLine->next) {   for (masterLine = template->lines;
3465      /* remember the indention level; we may need it for new lines */       masterLine && (tmplLine = lineDup(masterLine));
3466      if (tmplLine->numElements)       lineFree(tmplLine), masterLine = masterLine->next)
3467   indent = tmplLine->indent;   {
3468        dbgPrintf("addNewKernel processing %d\n", tmplLine->type);
3469    
3470      /* skip comments */      /* skip comments */
3471      chptr = tmplLine->indent;      chptr = tmplLine->indent;
3472      while (*chptr && isspace(*chptr)) chptr++;      while (*chptr && isspace(*chptr)) chptr++;
3473      if (*chptr == '#') continue;      if (*chptr == '#') continue;
3474    
3475      /* we don't need an initrd here */      if (iskernel(tmplLine->type) && tmplLine->numElements >= 2) {
3476      if (tmplLine->type == LT_INITRD && !newKernelInitrd) continue;   if (!template->multiboot && (needs & NEED_MB)) {
3477        /* it's not a multiboot template and this is the kernel
3478              if (tmplLine->type == LT_KERNEL &&       * line.  Try to be intelligent about inserting the
3479                  !template->multiboot && (needs & KERNEL_MB)) {       * hypervisor at the same time.
3480                  struct singleLine *l;       */
3481                  needs &= ~ KERNEL_MB;      if (config->cfi->mbHyperFirst) {
3482     /* insert the hypervisor first */
3483                  l = addLine(new, config->cfi, LT_KERNEL,   newLine = addLine(new, config->cfi, LT_HYPER,
3484                                    config->secondaryIndent,    tmplLine->indent,
3485                                    newMBKernel + strlen(prefix));    newMBKernel + strlen(prefix));
3486                     /* set up for adding the kernel line */
3487                  tmplLine = lastLine;   free(tmplLine->indent);
3488                  if (!new->lines) {   tmplLine->indent = strdup(config->secondaryIndent);
3489                      new->lines = l;   needs &= ~NEED_MB;
3490                  } else {      }
3491                      newLine->next = l;      if (needs & NEED_KERNEL) {
3492                      newLine = l;   /* use addLineTmpl to preserve line elements,
3493                  }   * otherwise we could just call addLine.  Unfortunately
3494                  continue;   * this means making some changes to the template
3495              } else if (tmplLine->type == LT_KERNEL &&   * such as the indent change above and the type
3496                         template->multiboot && !new->multiboot) {   * change below.
3497                  continue; /* don't need multiboot kernel here */   */
3498              }   struct keywordTypes * mbm_kw =
3499        getKeywordByType(LT_MBMODULE, config->cfi);
3500      if (!new->lines) {   if (mbm_kw) {
3501   newLine = malloc(sizeof(*newLine));      tmplLine->type = LT_MBMODULE;
3502   new->lines = newLine;      free(tmplLine->elements[0].item);
3503      } else {      tmplLine->elements[0].item = strdup(mbm_kw->key);
3504   newLine->next = malloc(sizeof(*newLine));   }
3505   newLine = newLine->next;   newLine = addLineTmpl(new, tmplLine, newLine,
3506      }        newKernelPath + strlen(prefix), config->cfi);
3507     needs &= ~NEED_KERNEL;
3508        }
3509        if (needs & NEED_MB) { /* !mbHyperFirst */
3510     newLine = addLine(new, config->cfi, LT_HYPER,
3511      config->secondaryIndent,
3512      newMBKernel + strlen(prefix));
3513     needs &= ~NEED_MB;
3514        }
3515     } else if (needs & NEED_KERNEL) {
3516        newLine = addLineTmpl(new, tmplLine, newLine,
3517      newKernelPath + strlen(prefix), config->cfi);
3518        needs &= ~NEED_KERNEL;
3519     }
3520    
3521        } else if (tmplLine->type == LT_HYPER &&
3522           tmplLine->numElements >= 2) {
3523     if (needs & NEED_MB) {
3524        newLine = addLineTmpl(new, tmplLine, newLine,
3525      newMBKernel + strlen(prefix), config->cfi);
3526        needs &= ~NEED_MB;
3527     }
3528    
3529      newLine->indent = strdup(tmplLine->indent);      } else if (tmplLine->type == LT_MBMODULE &&
3530      newLine->next = NULL;         tmplLine->numElements >= 2) {
3531      newLine->type = tmplLine->type;   if (new->multiboot) {
3532      newLine->numElements = tmplLine->numElements;      if (needs & NEED_KERNEL) {
3533      newLine->elements = malloc(sizeof(*newLine->elements) *   newLine = addLineTmpl(new, tmplLine, newLine,
3534      newLine->numElements);        newKernelPath +
3535      for (i = 0; i < newLine->numElements; i++) {        strlen(prefix), config->cfi);
3536   newLine->elements[i].item = strdup(tmplLine->elements[i].item);   needs &= ~NEED_KERNEL;
3537   newLine->elements[i].indent =      } else if (config->cfi->mbInitRdIsModule &&
3538   strdup(tmplLine->elements[i].indent);         (needs & NEED_INITRD)) {
3539      }   char *initrdVal;
3540     initrdVal = getInitrdVal(config, prefix, tmplLine,
3541              lastLine = tmplLine;   newKernelInitrd, extraInitrds,
3542      if (tmplLine->type == LT_KERNEL && tmplLine->numElements >= 2) {   extraInitrdCount);
3543                  char * repl;   newLine = addLineTmpl(new, tmplLine, newLine,
3544                  if (!template->multiboot) {        initrdVal, config->cfi);
3545                      needs &= ~KERNEL_KERNEL;   free(initrdVal);
3546                      repl = newKernelPath;   needs &= ~NEED_INITRD;
3547                  } else {      }
3548                      needs &= ~KERNEL_MB;   } else if (needs & NEED_KERNEL) {
3549                      repl = newMBKernel;      /* template is multi but new is not,
3550                  }       * insert the kernel in the first module slot
3551                  if (new->multiboot && !template->multiboot) {       */
3552                      free(newLine->elements[0].item);      tmplLine->type = preferredLineType(LT_KERNEL, config->cfi);
3553                      newLine->elements[0].item = strdup("module");      free(tmplLine->elements[0].item);
3554                      newLine->type = LT_MBMODULE;      tmplLine->elements[0].item =
3555                  }   strdup(getKeywordByType(tmplLine->type,
3556   free(newLine->elements[1].item);   config->cfi)->key);
3557                  rootspec = getRootSpecifier(tmplLine->elements[1].item);      newLine = addLineTmpl(new, tmplLine, newLine,
3558                  if (rootspec != NULL) {    newKernelPath + strlen(prefix),
3559                      newLine->elements[1].item = sdupprintf("%s%s",    config->cfi);
3560                                                             rootspec,      needs &= ~NEED_KERNEL;
3561                                                             repl +   } else if (needs & NEED_INITRD) {
3562                                                             strlen(prefix));      char *initrdVal;
3563                  } else {      /* template is multi but new is not,
3564                      newLine->elements[1].item = strdup(repl +       * insert the initrd in the second module slot
3565                                                         strlen(prefix));       */
3566                  }      tmplLine->type = preferredLineType(LT_INITRD, config->cfi);
3567              } else if (tmplLine->type == LT_MBMODULE &&      free(tmplLine->elements[0].item);
3568                         tmplLine->numElements >= 2 && (needs & KERNEL_KERNEL)) {      tmplLine->elements[0].item =
3569                  needs &= ~KERNEL_KERNEL;   strdup(getKeywordByType(tmplLine->type,
3570                  if (!new->multiboot && template->multiboot) {   config->cfi)->key);
3571                      free(newLine->elements[0].item);      initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3572                      newLine->elements[0].item = strdup("kernel");      newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3573                      newLine->type = LT_KERNEL;      free(initrdVal);
3574                  }      needs &= ~NEED_INITRD;
3575   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;  
3576    
3577   for (i = 1; i < newLine->numElements; i++) {      } else if (isinitrd(tmplLine->type) && tmplLine->numElements >= 2) {
3578      free(newLine->elements[i].item);   if (needs & NEED_INITRD &&
3579      free(newLine->elements[i].indent);      new->multiboot && !template->multiboot &&
3580        config->cfi->mbInitRdIsModule) {
3581        /* make sure we don't insert the module initrd
3582         * before the module kernel... if we don't do it here,
3583         * it will be inserted following the template.
3584         */
3585        if (!needs & NEED_KERNEL) {
3586     char *initrdVal;
3587    
3588     initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3589     newLine = addLine(new, config->cfi, LT_MBMODULE,
3590      config->secondaryIndent,
3591      initrdVal);
3592     free(initrdVal);
3593     needs &= ~NEED_INITRD;
3594        }
3595     } else if (needs & NEED_INITRD) {
3596        char *initrdVal;
3597        initrdVal = getInitrdVal(config, prefix, tmplLine, newKernelInitrd, extraInitrds, extraInitrdCount);
3598        newLine = addLineTmpl(new, tmplLine, newLine, initrdVal, config->cfi);
3599        free(initrdVal);
3600        needs &= ~NEED_INITRD;
3601   }   }
3602    
3603   newLine->elements[1].item = strdup(newKernelTitle);      } else if (tmplLine->type == LT_MENUENTRY &&
3604   newLine->elements[1].indent = strdup("");         (needs & NEED_TITLE)) {
3605   newLine->numElements = 2;   requote(tmplLine, config->cfi);
3606     char *nkt = malloc(strlen(newKernelTitle)+3);
3607     strcpy(nkt, "'");
3608     strcat(nkt, newKernelTitle);
3609     strcat(nkt, "'");
3610     newLine = addLineTmpl(new, tmplLine, newLine, nkt, config->cfi);
3611     free(nkt);
3612     needs &= ~NEED_TITLE;
3613      } else if (tmplLine->type == LT_TITLE &&      } else if (tmplLine->type == LT_TITLE &&
3614                         config->cfi->titleBracketed &&         (needs & NEED_TITLE)) {
3615                         tmplLine->numElements == 1) {   if (tmplLine->numElements >= 2) {
3616                  needs &= ~KERNEL_TITLE;      newLine = addLineTmpl(new, tmplLine, newLine,
3617                  free(newLine->elements[0].item);    newKernelTitle, config->cfi);
3618                  free(newLine->elements[0].indent);      needs &= ~NEED_TITLE;
3619                  newLine->elements = malloc(sizeof(*newLine->elements) *   } else if (tmplLine->numElements == 1 &&
3620                                             newLine->numElements);     config->cfi->titleBracketed) {
3621        /* addLineTmpl doesn't handle titleBracketed */
3622                  newLine->elements[0].item = malloc(strlen(newKernelTitle) + 3);      newLine = addLine(new, config->cfi, LT_TITLE,
3623                  sprintf(newLine->elements[0].item, "[%s]", newKernelTitle);        tmplLine->indent, newKernelTitle);
3624                  newLine->elements[0].indent = strdup("");      needs &= ~NEED_TITLE;
3625                  newLine->numElements = 1;   }
3626              }      } else if (tmplLine->type == LT_ECHO) {
3627        requote(tmplLine, config->cfi);
3628        static const char *prefix = "'Loading ";
3629        if (tmplLine->numElements > 1 &&
3630        strstr(tmplLine->elements[1].item, prefix) &&
3631        masterLine->next &&
3632        iskernel(masterLine->next->type)) {
3633     char *newTitle = malloc(strlen(prefix) +
3634     strlen(newKernelTitle) + 2);
3635    
3636     strcpy(newTitle, prefix);
3637     strcat(newTitle, newKernelTitle);
3638     strcat(newTitle, "'");
3639     newLine = addLine(new, config->cfi, LT_ECHO,
3640     tmplLine->indent, newTitle);
3641     free(newTitle);
3642        } else {
3643     /* pass through other lines from the template */
3644     newLine = addLineTmpl(new, tmplLine, newLine, NULL,
3645     config->cfi);
3646        }
3647        } else {
3648     /* pass through other lines from the template */
3649     newLine = addLineTmpl(new, tmplLine, newLine, NULL, config->cfi);
3650        }
3651   }   }
3652    
3653      } else {      } else {
3654   for (i = 0; config->cfi->keywords[i].key; i++) {   /* don't have a template, so start the entry with the
3655      if ((config->cfi->keywords[i].type == config->cfi->entrySeparator) || (config->cfi->keywords[i].type == LT_OTHER))   * appropriate starting line
3656     */
3657     switch (config->cfi->entryStart) {
3658        case LT_KERNEL:
3659        case LT_KERNEL_EFI:
3660     if (new->multiboot && config->cfi->mbHyperFirst) {
3661        /* fall through to LT_HYPER */
3662     } else {
3663        newLine = addLine(new, config->cfi,
3664              preferredLineType(LT_KERNEL, config->cfi),
3665          config->primaryIndent,
3666          newKernelPath + strlen(prefix));
3667        needs &= ~NEED_KERNEL;
3668        break;
3669     }
3670    
3671        case LT_HYPER:
3672     newLine = addLine(new, config->cfi, LT_HYPER,
3673      config->primaryIndent,
3674      newMBKernel + strlen(prefix));
3675     needs &= ~NEED_MB;
3676   break;   break;
         }  
3677    
3678   switch (config->cfi->keywords[i].type) {      case LT_MENUENTRY: {
3679      case LT_KERNEL:  needs &= ~KERNEL_KERNEL,   char *nkt = malloc(strlen(newKernelTitle)+3);
3680       chptr = newKernelPath + strlen(prefix);   strcpy(nkt, "'");
3681       type = LT_KERNEL; break;   strcat(nkt, newKernelTitle);
3682      case LT_TITLE:   needs &= ~KERNEL_TITLE, chptr = newKernelTitle;   strcat(nkt, "'");
3683       type = LT_TITLE; break;          newLine = addLine(new, config->cfi, LT_MENUENTRY,
3684      default:        config->primaryIndent, nkt);
3685                  /* zipl strikes again */   free(nkt);
3686                  if (config->cfi->titleBracketed) {   needs &= ~NEED_TITLE;
3687                      needs &= ~KERNEL_TITLE;   needs |= NEED_END;
3688                      chptr = newKernelTitle;   break;
3689                      type = LT_TITLE;      }
3690                      break;      case LT_TITLE:
3691                  } else {   if( useextlinuxmenu != 0 ){ // We just need useextlinuxmenu to not be zero (set above)
3692                      abort();   char * templabel;
3693                  }   int x = 0, y = 0;
3694   }  
3695     templabel = strdup(newKernelTitle);
3696     while( templabel[x]){
3697     if( templabel[x] == ' ' ){
3698     y = x;
3699     while( templabel[y] ){
3700     templabel[y] = templabel[y+1];
3701     y++;
3702     }
3703     }
3704     x++;
3705     }
3706     newLine = addLine(new, config->cfi, LT_TITLE,
3707      config->primaryIndent, templabel);
3708     free(templabel);
3709     }else{
3710     newLine = addLine(new, config->cfi, LT_TITLE,
3711      config->primaryIndent, newKernelTitle);
3712     }
3713     needs &= ~NEED_TITLE;
3714     break;
3715    
3716   newLine = addLine(new, config->cfi, type, config->primaryIndent, chptr);      default:
3717   new->lines = newLine;   abort();
3718     }
3719      }      }
3720    
3721      if (new->multiboot) {      /* add the remainder of the lines, i.e. those that either
3722          if (needs & KERNEL_MB)       * weren't present in the template, or in the case of no template,
3723              newLine = addLine(new, config->cfi, LT_KERNEL,       * all the lines following the entryStart.
3724                                config->secondaryIndent,       */
3725                                newMBKernel + strlen(prefix));      if (needs & NEED_TITLE) {
3726          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi, LT_TITLE,
3727              newLine = addLine(new, config->cfi, LT_MBMODULE,    config->secondaryIndent,
3728                                config->secondaryIndent,    newKernelTitle);
3729                                newKernelPath + strlen(prefix));   needs &= ~NEED_TITLE;
3730          /* don't need to check for title as it's guaranteed to have been      }
3731           * done as we only do multiboot with grub which uses title as      if ((needs & NEED_MB) && config->cfi->mbHyperFirst) {
3732           * a separator */   newLine = addLine(new, config->cfi, LT_HYPER,
3733          if (needs & KERNEL_INITRD && newKernelInitrd)    config->secondaryIndent,
3734              newLine = addLine(new, config->cfi, LT_MBMODULE,    newMBKernel + strlen(prefix));
3735                                config->secondaryIndent,   needs &= ~NEED_MB;
3736                                newKernelInitrd + strlen(prefix));      }
3737      } else {      if (needs & NEED_KERNEL) {
3738          if (needs & KERNEL_KERNEL)   newLine = addLine(new, config->cfi,
3739              newLine = addLine(new, config->cfi, LT_KERNEL,    (new->multiboot && getKeywordByType(LT_MBMODULE,
3740                                config->secondaryIndent,        config->cfi))
3741                                newKernelPath + strlen(prefix));     ? LT_MBMODULE
3742          if (needs & KERNEL_TITLE)   : preferredLineType(LT_KERNEL, config->cfi),
3743              newLine = addLine(new, config->cfi, LT_TITLE,    config->secondaryIndent,
3744                                config->secondaryIndent,    newKernelPath + strlen(prefix));
3745                                newKernelTitle);   needs &= ~NEED_KERNEL;
3746          if (needs & KERNEL_INITRD && newKernelInitrd)      }
3747              newLine = addLine(new, config->cfi, LT_INITRD,      if (needs & NEED_MB) {
3748                                config->secondaryIndent,   newLine = addLine(new, config->cfi, LT_HYPER,
3749                                newKernelInitrd + strlen(prefix));    config->secondaryIndent,
3750      newMBKernel + strlen(prefix));
3751     needs &= ~NEED_MB;
3752        }
3753        if (needs & NEED_INITRD) {
3754     char *initrdVal;
3755     initrdVal = getInitrdVal(config, prefix, NULL, newKernelInitrd, extraInitrds, extraInitrdCount);
3756     newLine = addLine(new, config->cfi,
3757      (new->multiboot && getKeywordByType(LT_MBMODULE,
3758          config->cfi))
3759       ? LT_MBMODULE
3760       : preferredLineType(LT_INITRD, config->cfi),
3761      config->secondaryIndent,
3762      initrdVal);
3763     free(initrdVal);
3764     needs &= ~NEED_INITRD;
3765        }
3766        if (needs & NEED_END) {
3767     newLine = addLine(new, config->cfi, LT_ENTRY_END,
3768     config->secondaryIndent, NULL);
3769     needs &= ~NEED_END;
3770        }
3771    
3772        if (needs) {
3773     printf(_("grubby: needs=%d, aborting\n"), needs);
3774     abort();
3775      }      }
3776    
3777      if (updateImage(config, "0", prefix, newKernelArgs, NULL,      if (updateImage(config, "0", prefix, newKernelArgs, NULL,
# Line 2274  int addNewKernel(struct grubConfig * con Line 3780  int addNewKernel(struct grubConfig * con
3780      return 0;      return 0;
3781  }  }
3782    
3783    static void traceback(int signum)
3784    {
3785        void *array[40];
3786        size_t size;
3787    
3788        signal(SIGSEGV, SIG_DFL);
3789        memset(array, '\0', sizeof (array));
3790        size = backtrace(array, 40);
3791    
3792        fprintf(stderr, "grubby received SIGSEGV!  Backtrace (%ld):\n",
3793                (unsigned long)size);
3794        backtrace_symbols_fd(array, size, STDERR_FILENO);
3795        exit(1);
3796    }
3797    
3798  int main(int argc, const char ** argv) {  int main(int argc, const char ** argv) {
3799      poptContext optCon;      poptContext optCon;
3800      char * grubConfig = NULL;      const char * grubConfig = NULL;
3801      char * outputFile = NULL;      char * outputFile = NULL;
3802      int arg = 0;      int arg = 0;
3803      int flags = 0;      int flags = 0;
3804      int badImageOkay = 0;      int badImageOkay = 0;
3805        int configureGrub2 = 0;
3806      int configureLilo = 0, configureELilo = 0, configureGrub = 0;      int configureLilo = 0, configureELilo = 0, configureGrub = 0;
3807      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;      int configureYaboot = 0, configureSilo = 0, configureZipl = 0;
3808        int configureExtLinux = 0;
3809      int bootloaderProbe = 0;      int bootloaderProbe = 0;
3810        int extraInitrdCount = 0;
3811      char * updateKernelPath = NULL;      char * updateKernelPath = NULL;
3812      char * newKernelPath = NULL;      char * newKernelPath = NULL;
3813      char * removeKernelPath = NULL;      char * removeKernelPath = NULL;
# Line 2299  int main(int argc, const char ** argv) { Line 3823  int main(int argc, const char ** argv) {
3823      char * defaultKernel = NULL;      char * defaultKernel = NULL;
3824      char * removeArgs = NULL;      char * removeArgs = NULL;
3825      char * kernelInfo = NULL;      char * kernelInfo = NULL;
3826        char * extraInitrds[MAX_EXTRA_INITRDS] = { NULL };
3827      const char * chptr = NULL;      const char * chptr = NULL;
3828      struct configFileInfo * cfi = NULL;      struct configFileInfo * cfi = NULL;
3829      struct grubConfig * config;      struct grubConfig * config;
3830      struct singleEntry * template = NULL;      struct singleEntry * template = NULL;
3831      int copyDefault = 0, makeDefault = 0;      int copyDefault = 0, makeDefault = 0;
3832      int displayDefault = 0;      int displayDefault = 0;
3833        int displayDefaultIndex = 0;
3834        int displayDefaultTitle = 0;
3835        int defaultIndex = -1;
3836      struct poptOption options[] = {      struct poptOption options[] = {
3837   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,   { "add-kernel", 0, POPT_ARG_STRING, &newKernelPath, 0,
3838      _("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 3850  int main(int argc, const char ** argv) {
3850   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,   { "boot-filesystem", 0, POPT_ARG_STRING, &bootPrefix, 0,
3851      _("filestystem which contains /boot directory (for testing only)"),      _("filestystem which contains /boot directory (for testing only)"),
3852      _("bootfs") },      _("bootfs") },
3853  #if defined(__i386__) || defined(__x86_64__)  #if defined(__i386__) || defined(__x86_64__) || defined (__powerpc64__) || defined (__ia64__)
3854   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,   { "bootloader-probe", 0, POPT_ARG_NONE, &bootloaderProbe, 0,
3855      _("check if lilo is installed on lilo.conf boot sector") },      _("check which bootloader is installed on boot sector") },
3856  #endif  #endif
3857   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,   { "config-file", 'c', POPT_ARG_STRING, &grubConfig, 0,
3858      _("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 3863  int main(int argc, const char ** argv) {
3863        "the kernel referenced by the default image does not exist, "        "the kernel referenced by the default image does not exist, "
3864        "the first linux entry whose kernel does exist is used as the "        "the first linux entry whose kernel does exist is used as the "
3865        "template"), NULL },        "template"), NULL },
3866     { "debug", 0, 0, &debug, 0,
3867        _("print debugging information for failures") },
3868   { "default-kernel", 0, 0, &displayDefault, 0,   { "default-kernel", 0, 0, &displayDefault, 0,
3869      _("display the path of the default kernel") },      _("display the path of the default kernel") },
3870     { "default-index", 0, 0, &displayDefaultIndex, 0,
3871        _("display the index of the default kernel") },
3872     { "default-title", 0, 0, &displayDefaultTitle, 0,
3873        _("display the title of the default kernel") },
3874   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,   { "elilo", 0, POPT_ARG_NONE, &configureELilo, 0,
3875      _("configure elilo bootloader") },      _("configure elilo bootloader") },
3876     { "efi", 0, POPT_ARG_NONE, &isEfi, 0,
3877        _("force grub2 stanzas to use efi") },
3878     { "extlinux", 0, POPT_ARG_NONE, &configureExtLinux, 0,
3879        _("configure extlinux bootloader (from syslinux)") },
3880   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,   { "grub", 0, POPT_ARG_NONE, &configureGrub, 0,
3881      _("configure grub bootloader") },      _("configure grub bootloader") },
3882     { "grub2", 0, POPT_ARG_NONE, &configureGrub2, 0,
3883        _("configure grub2 bootloader") },
3884   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,   { "info", 0, POPT_ARG_STRING, &kernelInfo, 0,
3885      _("display boot information for specified kernel"),      _("display boot information for specified kernel"),
3886      _("kernel-path") },      _("kernel-path") },
3887   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,   { "initrd", 0, POPT_ARG_STRING, &newKernelInitrd, 0,
3888      _("initrd image for the new kernel"), _("initrd-path") },      _("initrd image for the new kernel"), _("initrd-path") },
3889     { "extra-initrd", 'i', POPT_ARG_STRING, NULL, 'i',
3890        _("auxiliary initrd image for things other than the new kernel"), _("initrd-path") },
3891   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,   { "lilo", 0, POPT_ARG_NONE, &configureLilo, 0,
3892      _("configure lilo bootloader") },      _("configure lilo bootloader") },
3893   { "make-default", 0, 0, &makeDefault, 0,   { "make-default", 0, 0, &makeDefault, 0,
# Line 2365  int main(int argc, const char ** argv) { Line 3907  int main(int argc, const char ** argv) {
3907   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,   { "set-default", 0, POPT_ARG_STRING, &defaultKernel, 0,
3908      _("make the first entry referencing the specified kernel "      _("make the first entry referencing the specified kernel "
3909        "the default"), _("kernel-path") },        "the default"), _("kernel-path") },
3910     { "set-default-index", 0, POPT_ARG_INT, &defaultIndex, 0,
3911        _("make the given entry index the default entry"),
3912        _("entry-index") },
3913   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,   { "silo", 0, POPT_ARG_NONE, &configureSilo, 0,
3914      _("configure silo bootloader") },      _("configure silo bootloader") },
3915   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,   { "title", 0, POPT_ARG_STRING, &newKernelTitle, 0,
# Line 2382  int main(int argc, const char ** argv) { Line 3927  int main(int argc, const char ** argv) {
3927   { 0, 0, 0, 0, 0 }   { 0, 0, 0, 0, 0 }
3928      };      };
3929    
3930        useextlinuxmenu=0;
3931    
3932        signal(SIGSEGV, traceback);
3933    
3934        int i = 0;
3935        for (int j = 1; j < argc; j++)
3936     i += strlen(argv[j]) + 1;
3937        saved_command_line = malloc(i);
3938        if (!saved_command_line) {
3939     fprintf(stderr, "grubby: %m\n");
3940     exit(1);
3941        }
3942        saved_command_line[0] = '\0';
3943        for (int j = 1; j < argc; j++) {
3944     strcat(saved_command_line, argv[j]);
3945     strncat(saved_command_line, j == argc -1 ? "" : " ", 1);
3946        }
3947    
3948      optCon = poptGetContext("grubby", argc, argv, options, 0);      optCon = poptGetContext("grubby", argc, argv, options, 0);
3949      poptReadDefaultConfig(optCon, 1);      poptReadDefaultConfig(optCon, 1);
3950    
# Line 2391  int main(int argc, const char ** argv) { Line 3954  int main(int argc, const char ** argv) {
3954      printf("grubby version %s\n", VERSION);      printf("grubby version %s\n", VERSION);
3955      exit(0);      exit(0);
3956      break;      break;
3957      case 'i':
3958        if (extraInitrdCount < MAX_EXTRA_INITRDS) {
3959         extraInitrds[extraInitrdCount++] = strdup(poptGetOptArg(optCon));
3960        } else {
3961     fprintf(stderr, _("grubby: extra initrd maximum is %d\n"), extraInitrdCount);
3962     return 1;
3963        }
3964        break;
3965   }   }
3966      }      }
3967    
# Line 2406  int main(int argc, const char ** argv) { Line 3977  int main(int argc, const char ** argv) {
3977   return 1;   return 1;
3978      }      }
3979    
3980      if ((configureLilo + configureGrub + configureELilo +      if ((configureLilo + configureGrub2 + configureGrub + configureELilo +
3981   configureYaboot + configureSilo + configureZipl) > 1) {   configureYaboot + configureSilo + configureZipl +
3982     configureExtLinux ) > 1) {
3983   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));   fprintf(stderr, _("grubby: cannot specify multiple bootloaders\n"));
3984   return 1;   return 1;
3985      } else if (bootloaderProbe && grubConfig) {      } else if (bootloaderProbe && grubConfig) {
3986   fprintf(stderr,   fprintf(stderr,
3987      _("grubby: cannot specify config file with --bootloader-probe\n"));      _("grubby: cannot specify config file with --bootloader-probe\n"));
3988   return 1;   return 1;
3989        } else if (configureGrub2) {
3990     cfi = &grub2ConfigType;
3991      } else if (configureLilo) {      } else if (configureLilo) {
3992   cfi = &liloConfigType;   cfi = &liloConfigType;
3993      } else if (configureGrub) {      } else if (configureGrub) {
# Line 2426  int main(int argc, const char ** argv) { Line 4000  int main(int argc, const char ** argv) {
4000          cfi = &siloConfigType;          cfi = &siloConfigType;
4001      } else if (configureZipl) {      } else if (configureZipl) {
4002          cfi = &ziplConfigType;          cfi = &ziplConfigType;
4003        } else if (configureExtLinux) {
4004     cfi = &extlinuxConfigType;
4005     useextlinuxmenu=1;
4006      }      }
4007    
4008      if (!cfi) {      if (!cfi) {
4009            if (grub2FindConfig(&grub2ConfigType))
4010        cfi = &grub2ConfigType;
4011     else
4012        #ifdef __ia64__        #ifdef __ia64__
4013   cfi = &eliloConfigType;      cfi = &eliloConfigType;
4014        #elif __powerpc__        #elif __powerpc__
4015   cfi = &yabootConfigType;      cfi = &yabootConfigType;
4016        #elif __sparc__        #elif __sparc__
4017          cfi = &siloConfigType;              cfi = &siloConfigType;
4018        #elif __s390__        #elif __s390__
4019          cfi = &ziplConfigType;              cfi = &ziplConfigType;
4020        #elif __s390x__        #elif __s390x__
4021          cfi = &ziplConfigtype;              cfi = &ziplConfigtype;
4022        #else        #else
4023   cfi = &grubConfigType;      cfi = &grubConfigType;
4024        #endif        #endif
4025      }      }
4026    
4027      if (!grubConfig)      if (!grubConfig) {
4028   grubConfig = cfi->defaultConfig;   if (cfi->findConfig)
4029        grubConfig = cfi->findConfig(cfi);
4030     if (!grubConfig)
4031        grubConfig = cfi->defaultConfig;
4032        }
4033    
4034      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||      if (bootloaderProbe && (displayDefault || kernelInfo || newKernelVersion ||
4035    newKernelPath || removeKernelPath || makeDefault ||      newKernelPath || removeKernelPath || makeDefault ||
4036    defaultKernel)) {      defaultKernel || displayDefaultIndex || displayDefaultTitle ||
4037        (defaultIndex >= 0))) {
4038   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "   fprintf(stderr, _("grubby: --bootloader-probe may not be used with "
4039    "specified option"));    "specified option"));
4040   return 1;   return 1;
# Line 2465  int main(int argc, const char ** argv) { Line 4050  int main(int argc, const char ** argv) {
4050      if (newKernelPath && !newKernelTitle) {      if (newKernelPath && !newKernelTitle) {
4051   fprintf(stderr, _("grubby: kernel title must be specified\n"));   fprintf(stderr, _("grubby: kernel title must be specified\n"));
4052   return 1;   return 1;
4053      } else if (!newKernelPath && (newKernelTitle  || newKernelInitrd ||      } else if (!newKernelPath && (newKernelTitle  || copyDefault ||
4054    newKernelInitrd || copyDefault     ||    (newKernelInitrd && !updateKernelPath)||
4055    makeDefault)) {    makeDefault || extraInitrdCount > 0)) {
4056   fprintf(stderr, _("grubby: kernel path expected\n"));   fprintf(stderr, _("grubby: kernel path expected\n"));
4057   return 1;   return 1;
4058      }      }
# Line 2491  int main(int argc, const char ** argv) { Line 4076  int main(int argc, const char ** argv) {
4076   makeDefault = 1;   makeDefault = 1;
4077   defaultKernel = NULL;   defaultKernel = NULL;
4078      }      }
4079        else if (defaultKernel && (defaultIndex >= 0)) {
4080     fprintf(stderr, _("grubby: --set-default and --set-default-index "
4081      "may not be used together\n"));
4082     return 1;
4083        }
4084    
4085      if (!strcmp(grubConfig, "-") && !outputFile) {      if (grubConfig && !strcmp(grubConfig, "-") && !outputFile) {
4086   fprintf(stderr, _("grubby: output file must be specified if stdin "   fprintf(stderr, _("grubby: output file must be specified if stdin "
4087   "is used\n"));   "is used\n"));
4088   return 1;   return 1;
4089      }      }
4090    
4091      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel      if (!removeKernelPath && !newKernelPath && !displayDefault && !defaultKernel
4092   && !kernelInfo && !bootloaderProbe && !updateKernelPath   && !kernelInfo && !bootloaderProbe && !updateKernelPath
4093          && !removeMBKernel) {   && !removeMBKernel && !displayDefaultIndex && !displayDefaultTitle
4094     && (defaultIndex == -1)) {
4095   fprintf(stderr, _("grubby: no action specified\n"));   fprintf(stderr, _("grubby: no action specified\n"));
4096   return 1;   return 1;
4097      }      }
# Line 2520  int main(int argc, const char ** argv) { Line 4111  int main(int argc, const char ** argv) {
4111   bootPrefix = "";   bootPrefix = "";
4112      }      }
4113    
4114        if (!cfi->mbAllowExtraInitRds &&
4115     extraInitrdCount > 0) {
4116     fprintf(stderr, _("grubby: %s doesn't allow multiple initrds\n"), cfi->defaultConfig);
4117     return 1;
4118        }
4119    
4120      if (bootloaderProbe) {      if (bootloaderProbe) {
4121   int lrc = 0, grc = 0;   int lrc = 0, grc = 0, gr2c = 0, extrc = 0, yrc = 0, erc = 0;
4122   struct grubConfig * lconfig, * gconfig;   struct grubConfig * lconfig, * gconfig, * yconfig, * econfig;
4123    
4124     const char *grub2config = grub2FindConfig(&grub2ConfigType);
4125     if (grub2config) {
4126        gconfig = readConfig(grub2config, &grub2ConfigType);
4127        if (!gconfig)
4128     gr2c = 1;
4129        else
4130     gr2c = checkForGrub2(gconfig);
4131     }
4132    
4133   if (!access(grubConfigType.defaultConfig, F_OK)) {   const char *grubconfig = grubFindConfig(&grubConfigType);
4134      gconfig = readConfig(grubConfigType.defaultConfig, &grubConfigType);   if (!access(grubconfig, F_OK)) {
4135        gconfig = readConfig(grubconfig, &grubConfigType);
4136      if (!gconfig)      if (!gconfig)
4137   grc = 1;   grc = 1;
4138      else      else
# Line 2540  int main(int argc, const char ** argv) { Line 4147  int main(int argc, const char ** argv) {
4147   lrc = checkForLilo(lconfig);   lrc = checkForLilo(lconfig);
4148   }   }
4149    
4150   if (lrc == 1 || grc == 1) return 1;   if (!access(eliloConfigType.defaultConfig, F_OK)) {
4151        econfig = readConfig(eliloConfigType.defaultConfig,
4152     &eliloConfigType);
4153        if (!econfig)
4154     erc = 1;
4155        else
4156     erc = checkForElilo(econfig);
4157     }
4158    
4159     if (!access(extlinuxConfigType.defaultConfig, F_OK)) {
4160        lconfig = readConfig(extlinuxConfigType.defaultConfig, &extlinuxConfigType);
4161        if (!lconfig)
4162     extrc = 1;
4163        else
4164     extrc = checkForExtLinux(lconfig);
4165     }
4166    
4167    
4168     if (!access(yabootConfigType.defaultConfig, F_OK)) {
4169        yconfig = readConfig(yabootConfigType.defaultConfig,
4170     &yabootConfigType);
4171        if (!yconfig)
4172     yrc = 1;
4173        else
4174     yrc = checkForYaboot(yconfig);
4175     }
4176    
4177     if (lrc == 1 || grc == 1 || gr2c == 1 || extrc == 1 || yrc == 1 ||
4178     erc == 1)
4179        return 1;
4180    
4181   if (lrc == 2) printf("lilo\n");   if (lrc == 2) printf("lilo\n");
4182     if (gr2c == 2) printf("grub2\n");
4183   if (grc == 2) printf("grub\n");   if (grc == 2) printf("grub\n");
4184     if (extrc == 2) printf("extlinux\n");
4185     if (yrc == 2) printf("yaboot\n");
4186     if (erc == 2) printf("elilo\n");
4187    
4188   return 0;   return 0;
4189      }      }
# Line 2561  int main(int argc, const char ** argv) { Line 4201  int main(int argc, const char ** argv) {
4201   if (!entry) return 0;   if (!entry) return 0;
4202   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;   if (!suitableImage(entry, bootPrefix, 0, flags)) return 0;
4203    
4204   line = entry->lines;   line = getLineByType(LT_KERNEL|LT_HYPER|LT_KERNEL_EFI, entry->lines);
  while (line && line->type != LT_KERNEL) line = line->next;  
4205   if (!line) return 0;   if (!line) return 0;
4206    
4207          rootspec = getRootSpecifier(line->elements[1].item);          rootspec = getRootSpecifier(line->elements[1].item);
# Line 2570  int main(int argc, const char ** argv) { Line 4209  int main(int argc, const char ** argv) {
4209                 ((rootspec != NULL) ? strlen(rootspec) : 0));                 ((rootspec != NULL) ? strlen(rootspec) : 0));
4210    
4211   return 0;   return 0;
4212    
4213        } else if (displayDefaultTitle) {
4214     struct singleLine * line;
4215     struct singleEntry * entry;
4216    
4217     if (config->defaultImage == -1) return 0;
4218     entry = findEntryByIndex(config, config->defaultImage);
4219     if (!entry) return 0;
4220    
4221     if (!configureGrub2) {
4222      line = getLineByType(LT_TITLE, entry->lines);
4223      if (!line) return 0;
4224      printf("%s\n", line->elements[1].item);
4225    
4226     } else {
4227      char * title;
4228    
4229      dbgPrintf("This is GRUB2, default title is embeded in menuentry\n");
4230      line = getLineByType(LT_MENUENTRY, entry->lines);
4231      if (!line) return 0;
4232      title = grub2ExtractTitle(line);
4233      if (title)
4234        printf("%s\n", title);
4235     }
4236     return 0;
4237    
4238        } else if (displayDefaultIndex) {
4239            if (config->defaultImage == -1) return 0;
4240            printf("%i\n", config->defaultImage);
4241    
4242      } else if (kernelInfo)      } else if (kernelInfo)
4243   return displayInfo(config, kernelInfo, bootPrefix);   return displayInfo(config, kernelInfo, bootPrefix);
4244    
# Line 2581  int main(int argc, const char ** argv) { Line 4250  int main(int argc, const char ** argv) {
4250      markRemovedImage(config, removeKernelPath, bootPrefix);      markRemovedImage(config, removeKernelPath, bootPrefix);
4251      markRemovedImage(config, removeMBKernel, bootPrefix);      markRemovedImage(config, removeMBKernel, bootPrefix);
4252      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,      setDefaultImage(config, newKernelPath != NULL, defaultKernel, makeDefault,
4253      bootPrefix, flags);      bootPrefix, flags, defaultIndex);
4254      setFallbackImage(config, newKernelPath != NULL);      setFallbackImage(config, newKernelPath != NULL);
4255      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,      if (updateImage(config, updateKernelPath, bootPrefix, newKernelArgs,
4256                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;                      removeArgs, newMBKernelArgs, removeMBKernelArgs)) return 1;
4257        if (updateKernelPath && newKernelInitrd) {
4258                if (updateInitrd(config, updateKernelPath, bootPrefix,
4259                                 newKernelInitrd)) return 1;
4260        }
4261      if (addNewKernel(config, template, bootPrefix, newKernelPath,      if (addNewKernel(config, template, bootPrefix, newKernelPath,
4262                       newKernelTitle, newKernelArgs, newKernelInitrd,                       newKernelTitle, newKernelArgs, newKernelInitrd,
4263                         (const char **)extraInitrds, extraInitrdCount,
4264                       newMBKernel, newMBKernelArgs)) return 1;                       newMBKernel, newMBKernelArgs)) return 1;
4265            
4266    
# Line 2597  int main(int argc, const char ** argv) { Line 4271  int main(int argc, const char ** argv) {
4271      }      }
4272    
4273      if (!outputFile)      if (!outputFile)
4274   outputFile = grubConfig;   outputFile = (char *)grubConfig;
4275    
4276      return writeConfig(config, outputFile, bootPrefix);      return writeConfig(config, outputFile, bootPrefix);
4277  }  }

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